Home - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

The D programming language. Modern convenience. Modeling power. Native efficiency.

DConf 2013 is scheduled for May 1-3 in Menlo Park, California. Visit the conference website for more details including how to propose a session.

[your code here] Got a brief example illustrating D? Submit your code to the digitalmars.D forum specifying "[your code here]" in the title. Upon approval it will be showcased on a random schedule on D's homepage.
#!/usr/bin/env rdmd
// Computes average line length for standard input.
import std.stdio;

void main() {
    ulong lines = 0;
    double sumLength = 0;
    foreach (line; stdin.byLine()) {
        ++lines;
        sumLength += line.length;
    }
    writeln("Average line length: ",
        lines ? sumLength / lines : 0);
}
D is a language with C-like syntax and static typing. It pragmatically combines efficiency, control, and modeling power, with safety and programmer productivity.

Convenience

  • D allows writing large code fragments without redundantly specifying types, like dynamic languages do. On the other hand, static inference deduces types and other code properties, giving the best of both the static and the dynamic worlds.
    void main() {
    // Define an array of numbers, double[]. Compiler recognizes the common
    // type of all initializers.
    auto arr = [ 1, 2, 3.14, 5.1, 6 ];
    // Dictionary that maps string to int, type is spelled int[string]
    auto dictionary = [ "one" : 1, "two" : 2, "three" : 3 ];
    // Calls the min function defined below
    auto x = min(arr[0], dictionary["two"]);
}
// Type deduction works for function results. This is important for generic
// functions, such as min below, which works correctly for all comparable
// types.
auto min(T1, T2)(T1 lhs, T2 rhs) {
    return rhs < lhs ? rhs : lhs;
}
  • Automatic memory management makes for safe, simple, and robust code. D also supports scoped resource management (aka the RAII idiom) and scope statements for deterministic transactional code that is easy to write and read.
    import std.stdio;

class Widget { }

void main() {
    // Automatically managed.
    auto w = new Widget;
    // Code is executed in any case upon scope exit.
    scope(exit) { writeln("Exiting main."); }
    // File is closed deterministically at scope's end.
    foreach (line; File("text.txt").byLine()) {
        writeln(line);
    }
    writeln();
}
  • Built-in linear and associative arrays, slices, and ranges make daily programming simple and pleasant for tasks, both small and large.
    #!/usr/bin/env rdmd
import std.range, std.stdio;

// Compute average line length for stdin
void main() {
    ulong lines = 0, sumLength = 0;
    foreach (line; stdin.byLine()) {
        ++lines;
        sumLength += line.length;
    }
    writeln("Average line length: ",
        lines ? cast(double) sumLength / lines : 0.0);
}

Power

  • The best paradigm is to not impose something at the expense of others. D offers classic polymorphism, value semantics, functional style, generics, generative programming, contract programming, and more—all harmoniously integrated.
    // Interfaces and classes
interface Printable {
   void print(uint level)
   in { assert(level > 0); } // contract is part of the interface
}

// Interface implementation
class Widget : Printable {
   void print(uint level)
   in{ }
   body{ }
}

// Single inheritance of state
class ExtendedWidget : Widget {
   override void print(uint level)
   in { /* weakening precondition is okay */  }
   body {
       //... level may be 0 here ...
   }
}

// Immutable data shared across threads
immutable string programName = "demo";
// Mutable data is thread-local
int perThread = 42;
// Explicitly shared data
shared int perApp = 5;

// Structs have value semantics
struct BigNum {
    // intercept copying
    this(this) { }
    // intercept destructor
    ~this() { }
}

void main()
{
    // ...
}
  • D offers an innovative approach to concurrency, featuring true immutable data, message passing, no sharing by default, and controlled mutable sharing across threads. Read more.
  • From simple scripts to large projects, D has the breadth to scale with any application's needs: unit testing, information hiding, refined modularity, fast compilation, precise interfaces. Read more.

Efficiency

  • D compiles naturally to efficient native code.
  • D is designed such that most "obvious" code is fast and safe. On occasion a function might need to escape the confines of type safety for ultimate speed and control. For such rare cases D offers native pointers, type casts, access to any C function without any intervening translation, and even inline assembly code.
    import core.stdc.stdlib;

void livingDangerously() {
    // Access to C's malloc and free primitives
    auto buf = malloc(1024 * 1024);
    scope(exit) free(buf); // free automatically upon scope exit
    // Interprets memory as an array of floats
    auto floats = cast(float[]) buf[0 .. 1024 * 1024];
    // Even stack allocation is possible
    auto moreBuf = alloca(4096 * 100);
    //...
}

// Using inline asm for extra speed on x86
uint checked_multiply(uint x, uint y) {
    uint result;
    version (D_InlineAsm_X86) {
        // Inline assembler "sees" D variables.
        asm {
            mov     EAX,x        ;
            mul     EAX,y        ;
            mov     result,EAX   ;
            jc      Loverflow    ;
        }
        return result;
    } else {
        result = x * y;
        if (!y || x <= uint.max / y)
           return result;
   }
Loverflow:
   throw new Exception("multiply overflow");
}

void main()
{
    // ...
}
  • The @safe, @trusted, and @system modular attributes allow the programmer to best decide the safety-efficiency tradeoffs of an application, and have the compiler check for consistency. Read more.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Overview - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Overview

What is D?

D is a general purpose systems and applications programming language. It is a high level language, but retains the ability to write high performance code and interface directly with the operating system API's and with hardware. D is well suited to writing medium to large scale million line programs with teams of developers. D is easy to learn, provides many capabilities to aid the programmer, and is well suited to aggressive compiler optimization technology. D Man

D is not a scripting language, nor an interpreted language. It doesn't come with a VM, a religion, or an overriding philosophy. It's a practical language for practical programmers who need to get the job done quickly, reliably, and leave behind maintainable, easy to understand code.

D is the culmination of decades of experience implementing compilers for many diverse languages, and attempting to construct large projects using those languages. D draws inspiration from those other languages (most especially C++) and tempers it with experience and real world practicality.

Why D?

Why, indeed. Who needs another programming language?

The software industry has come a long way since the C language was invented. Many new concepts were added to the language with C++, but backwards compatibility with C was maintained, including compatibility with nearly all the weaknesses of the original design. There have been many attempts to fix those weaknesses, but the compatibility issue frustrates it. Meanwhile, both C and C++ undergo a constant accretion of new features. These new features must be carefully fitted into the existing structure without requiring rewriting old code. The end result is very complicated - the C standard is nearly 500 pages, and the C++ standard is about 750 pages! C++ is a difficult and costly language to implement, resulting in implementation variations that make it frustrating to write fully portable C++ code.

C++ implements things like resizable arrays and string concatenation as part of the standard library, not as part of the core language.

Can the power and capability of C++ be extracted, redesigned, and recast into a language that is simple, orthogonal, and practical? Can it all be put into a package that is easy for compiler writers to correctly implement, and which enables compilers to efficiently generate aggressively optimized code?

Modern compiler technology has progressed to the point where language features for the purpose of compensating for primitive compiler technology can be omitted. (An example of this would be the ‘register’ keyword in C, a more subtle example is the macro preprocessor in C.) We can rely on modern compiler optimization technology to not need language features necessary to get acceptable code quality out of primitive compilers.

Major Design Goals of D

Everything in designing a language is a tradeoff. Keeping some principles in mind will help to make the right decisions.

  1. Make it easier to write code that is portable from compiler to compiler, machine to machine, and operating system to operating system. Eliminate undefined and implementation defined behaviors as much as practical.
  2. Provide syntactic and semantic constructs that eliminate or at least reduce common mistakes. Reduce or even eliminate the need for third party static code checkers.
  3. Support memory safe programming.
  4. Support multi-paradigm programming, i.e. at a minimum support imperative, structured, object oriented, generic and even functional programming paradigms.
  5. Make doing things the right way easier than the wrong way.
  6. Have a short learning curve for programmers comfortable with programming in C, C++ or Java.
  7. Provide low level bare metal access as required. Provide a means for the advanced programmer to escape checking as necessary.
  8. Be compatible with the local C application binary interface.
  9. Where D code looks the same as C code, have it either behave the same or issue an error.
  10. Have a context-free grammar. Successful parsing must not require semantic analysis.
  11. Easily support writing internationalized applications.
  12. Incorporate Contract Programming and unit testing methodology.
  13. Be able to build lightweight, standalone programs.
  14. Reduce the costs of creating documentation.
  15. Provide sufficient semantics to enable advances in compiler optimization technology.
  16. Cater to the needs of numerical analysis programmers.
  17. Obviously, sometimes these goals will conflict. Resolution will be in favor of usability.

Features To Keep

The general look of D is like C and C++. This makes it easier to learn and port code to D. Transitioning from C/C++ to D should feel natural. The programmer will not have to learn an entirely new way of doing things.

Using D will not mean that the programmer will become restricted to a specialized runtime vm (virtual machine) like the Java vm or the Smalltalk vm. There is no D vm, it's a straightforward compiler that generates linkable object files. D connects to the operating system just like C does. The usual familiar tools like make will fit right in with D development.

  • The general look and feel of C/C++ is maintained. It uses the same algebraic syntax, most of the same expression and statement forms, and the general layout.
  • D programs can be written either in C style function-and-data, C++ style object-oriented, C++ style template metaprogramming, or any mix of the three.
  • The compile/link/debug development model is carried forward, although nothing precludes D from being compiled into bytecode and interpreted.
  • Exception handling. More and more experience with exception handling shows it to be a superior way to handle errors than the C traditional method of using error codes and errno globals.
  • Runtime Type Identification. This is partially implemented in C++; in D it is taken to its next logical step. Fully supporting it enables better garbage collection, better debugger support, more automated persistence, etc.
  • D maintains function link compatibility with the C calling conventions. This makes it possible for D programs to access operating system API's directly. Programmers' knowledge and experience with existing programming API's and paradigms can be carried forward to D with minimal effort.
  • Operator overloading. D programs can overload operators enabling extension of the basic types with user defined types.
  • Template Metaprogramming. Templates are a way to implement generic programming. Other ways include using macros or having a variant data type. Using macros is out. Variants are straightforward, but inefficient and lack type checking. The difficulties with C++ templates are their complexity, they don't fit well into the syntax of the language, all the various rules for conversions and overloading fitted on top of it, etc. D offers a much simpler way of doing templates.
  • RAII (Resource Acquisition Is Initialization). RAII techniques are an essential component of writing reliable software.
  • Down and dirty programming. D retains the ability to do down-and-dirty programming without resorting to referring to external modules compiled in a different language. Sometimes, it's just necessary to coerce a pointer or dip into assembly when doing systems work. D's goal is not to prevent down and dirty programming, but to minimize the need for it in solving routine coding tasks.

Features To Drop

  • C source code compatibility. Extensions to C that maintain source compatibility have already been done (C++ and ObjectiveC). Further work in this area is hampered by so much legacy code it is unlikely that significant improvements can be made.
  • Link compatibility with C++. The C++ runtime object model is just too complicated - properly supporting it would essentially imply making D a full C++ compiler too.
  • The C preprocessor. Macro processing is an easy way to extend a language, adding in faux features that aren't really there (invisible to the symbolic debugger). Conditional compilation, layered with #include text, macros, token concatenation, etc., essentially forms not one language but two merged together with no obvious distinction between them. Even worse (or perhaps for the best) the C preprocessor is a very primitive macro language. It's time to step back, look at what the preprocessor is used for, and design support for those capabilities directly into the language.
  • Multiple inheritance. It's a complex feature of debatable value. It's very difficult to implement in an efficient manner, and compilers are prone to many bugs in implementing it. Nearly all the value of MI can be handled with single inheritance coupled with interfaces and aggregation. What's left does not justify the weight of MI implementation.
  • Namespaces. An attempt to deal with the problems resulting from linking together independently developed pieces of code that have conflicting names. The idea of modules is simpler and works much better.
  • Tag name space. This misfeature of C is where the tag names of structs are in a separate but parallel symbol table. C++ attempted to merge the tag name space with the regular name space, while retaining backward compatibility with legacy C code. The result is needlessly confusing.
  • Forward declarations. C compilers semantically only know about what has lexically preceded the current state. C++ extends this a little, in that class members can rely on forward referenced class members. D takes this to its logical conclusion, forward declarations are no longer necessary at the module level. Functions can be defined in a natural order rather than the typical inside-out order commonly used in C programs to avoid writing forward declarations.
  • Include files. A major cause of slow compiles as each compilation unit must reparse enormous quantities of header files. Include files should be done as importing a symbol table.
  • Trigraphs and digraphs. Unicode is the future.
  • Non-virtual member functions. In C++, a class designer decides in advance if a function is to be virtual or not. Forgetting to retrofit the base class member function to be virtual when the function gets overridden is a common (and very hard to find) coding error. Making all member functions virtual, and letting the compiler decide if there are no overrides and hence can be converted to non-virtual, is much more reliable.
  • Bit fields of arbitrary size. Bit fields are a complex, inefficient feature rarely used.
  • Support for 16 bit computers. No consideration is given in D for mixed near/far pointers and all the machinations necessary to generate good 16 bit code. The D language design assumes at least a 32 bit flat memory space. D will fit smoothly into 64 bit architectures.
  • Mutual dependence of compiler passes. In C++, successfully parsing the source text relies on having a symbol table, and on the various preprocessor commands. This makes it impossible to preparse C++ source, and makes writing code analyzers and syntax directed editors painfully difficult to do correctly.
  • Compiler complexity. Reducing the complexity of an implementation makes it more likely that multiple, correct implementations are available.
  • Dumbed down floating point. If one is using hardware that implements modern floating point, it should be available to the programmer rather than having floating point support dumbed down to the lowest common denominator among machines. In particular, a D implementation must support IEEE 754 arithmetic and if extended precision is available it must be supported.
  • Template overloading of < and > symbols. This choice has caused years of bugs, grief, and confusion for programmers, C++ implementors, and C++ source parsing tool vendors. It makes it impossible to parse C++ code correctly without doing a nearly complete C++ compiler. D uses !( and ) which fit neatly and unambiguously into the grammar.

Who D is For

  • Programmers who routinely use lint or similar code analysis tools to eliminate bugs before the code is even compiled.
  • People who compile with maximum warning levels turned on and who instruct the compiler to treat warnings as errors.
  • Programming managers who are forced to rely on programming style guidelines to avoid common C bugs.
  • Those who decide the promise of C++ object oriented programming is not fulfilled due to the complexity of it.
  • Programmers who enjoy the expressive power of C++ but are frustrated by the need to expend much effort explicitly managing memory and finding pointer bugs.
  • Projects that need built-in testing and verification.
  • Teams who write apps with a million lines of code in it.
  • Programmers who think the language should provide enough features to obviate the continual necessity to manipulate pointers directly.
  • Numerical programmers. D has many features to directly support features needed by numerics programmers, like extended floating point precision, core support for complex and imaginary floating types and defined behavior for NaN's and infinities. (These are added in the new C99 standard, but not in C++.)
  • Programmers who write half their application in scripting languages like Ruby and Python, and the other half in C++ to speed up the bottlenecks. D has many of the productivity features of Ruby and Python, making it possible to write the entire app in one language.
  • D's lexical analyzer and parser are totally independent of each other and of the semantic analyzer. This means it is easy to write simple tools to manipulate D source perfectly without having to build a full compiler. It also means that source code can be transmitted in tokenized form for specialized applications.

Who D is Not For

  • Realistically, nobody is going to convert million line C or C++ programs into D. Since D does not compile unmodified C/C++ source code, D is not for legacy apps. (However, D supports legacy C API's very well. D can connect directly to any code that exposes a C interface.)
  • As a first programming language - Basic or Java is more suitable for beginners. D makes an excellent second language for intermediate to advanced programmers.
  • Language purists. D is a practical language, and each feature of it is evaluated in that light, rather than by an ideal. For example, D has constructs and semantics that virtually eliminate the need for pointers for ordinary tasks. But pointers are still there, because sometimes the rules need to be broken. Similarly, casts are still there for those times when the typing system needs to be overridden.

Major Features of D

This section lists some of the more interesting features of D in various categories.

Object Oriented Programming

Classes

D's object oriented nature comes from classes. The inheritance model is single inheritance enhanced with interfaces. The class Object sits at the root of the inheritance hierarchy, so all classes implement a common set of functionality. Classes are instantiated by reference, and so complex code to clean up after exceptions is not required.

Operator Overloading

Classes can be crafted that work with existing operators to extend the type system to support new types. An example would be creating a bignumber class and then overloading the +, -, * and / operators to enable using ordinary algebraic syntax with them.

Functional Programming

Functional programming has a lot to offer in terms of encapsulation, concurrent programming, memory safety, and composition. D's support for functional style programming include:

  • Pure functions
  • Immutable types and data structures
  • Lambda functions and closures

Productivity

Modules

Source files have a one-to-one correspondence with modules. Instead of #include'ing the text of a file of declarations, just import the module. There is no need to worry about multiple imports of the same module, no need to wrapper header files with #ifndef/#endif or #pragma once kludges, etc.

Declaration vs Definition

C++ usually requires that functions and classes be declared twice - the declaration that goes in the .h header file, and the definition that goes in the .c source file. This is an error prone and tedious process. Obviously, the programmer should only need to write it once, and the compiler should then extract the declaration information and make it available for symbolic importing. This is exactly how D works.

Example:

class ABC
{
    int func() { return 7; }
    static int z = 7;
}
int q;

There is no longer a need for a separate definition of member functions, static members, externs, nor for clumsy syntaxes like:

int ABC::func() { return 7; }
int ABC::z = 7;
extern int q;

Note: Of course, in C++, trivial functions like { return 7; } are written inline too, but complex ones are not. In addition, if there are any forward references, the functions need to be prototyped. The following will not work in C++:

class Foo
{
    int foo(Bar *c) { return c->bar(); }
};

class Bar
{
  public:
    int bar() { return 3; }
};

But the equivalent D code will work:

class Foo
{
    int foo(Bar c) { return c.bar; }
}

class Bar
{
    int bar() { return 3; }
}

Whether a D function is inlined or not is determined by the optimizer settings.

Templates

D templates offer a clean way to support generic programming while offering the power of partial specialization. Template classes and template functions are available, along with variadic template arguments and tuples.

Associative Arrays

Associative arrays are arrays with an arbitrary data type as the index rather than being limited to an integer index. In essence, associated arrays are hash tables. Associative arrays make it easy to build fast, efficient, bug-free symbol tables.

Documentation

Documentation has traditionally been done twice - first there are comments documenting what a function does, and then this gets rewritten into a separate html or man page. And naturally, over time, they'll tend to diverge as the code gets updated and the separate documentation doesn't. Being able to generate the requisite polished documentation directly from the comments embedded in the source will not only cut the time in half needed to prepare documentation, it will make it much easier to keep the documentation in sync with the code. Ddoc is the specification for the D documentation generator. This page was generated by Ddoc, too.

Although third party tools exist to do this for C++, they have some serious shortcomings:

  • It is spectacularly difficult to parse C++ 100% correctly. To do so really requires a full C++ compiler. Third party tools tend to parse only a subset of C++ correctly, so their use will constrain the source code to that subset.
  • Different compilers support different versions of C++ and have different extensions to C++. Third party tools have a problem matching all these variations.
  • Third party tools may not be available for all the desired platforms, and they're necessarily on a different upgrade cycle from the compilers.
  • Having it builtin to the compiler means it is standardized across all D implementations. Having a default one ready to go at all times means it is far more likely to be used.

Functions

D has the expected support for ordinary functions including global functions, overloaded functions, inlining of functions, member functions, virtual functions, function pointers, etc. In addition:

Nested Functions

Functions can be nested within other functions. This is highly useful for code factoring, locality, and function closure techniques.

Function Literals

Anonymous functions can be embedded directly into an expression.

Dynamic Closures

Nested functions and class member functions can be referenced with closures (also called delegates), making generic programming much easier and type safe.

In, Out, and Ref Parameters

Not only does specifying this help make functions more self-documenting, it eliminates much of the necessity for pointers without sacrificing anything, and it opens up possibilities for more compiler help in finding coding problems.

Such makes it possible for D to directly interface to a wider variety of foreign API's. There would be no need for workarounds like "Interface Definition Languages".

Arrays

C arrays have several faults that can be corrected:

  • Dimension information is not carried around with the array, and so has to be stored and passed separately. The classic example of this are the argc and argv parameters to main(int argc, char *argv[]). (In D, main is declared as main(char[][] args).)
  • Arrays are not first class objects. When an array is passed to a function, it is converted to a pointer, even though the prototype confusingly says it's an array. When this conversion happens, all array type information gets lost.
  • C arrays cannot be resized. This means that even simple aggregates like a stack need to be constructed as a complex class.
  • C arrays cannot be bounds checked, because they don't know what the array bounds are.
  • Arrays are declared with the [] after the identifier. This leads to very clumsy syntax to declare things like a pointer to an array:
    int (*array)[3];

    In D, the [] for the array go on the left:

    int[3]* array;		// declares a pointer to an array of 3 ints
long[] func(int x);	// declares a function returning an array of longs

    which is much simpler to understand.

D arrays come in several varieties: pointers, static arrays, dynamic arrays, and associative arrays.

See Arrays.

Strings

String manipulation is so common, and so clumsy in C and C++, that it needs direct support in the language. Modern languages handle string concatenation, copying, etc., and so does D. Strings are a direct consequence of improved array handling.

Resource Management

Automatic Memory Management

D memory allocation is fully garbage collected. Empirical experience suggests that a lot of the complicated features of C++ are necessary in order to manage memory deallocation. With garbage collection, the language gets much simpler.

Garbage collection eliminates the tedious, error prone memory allocation tracking code necessary in C and C++. This not only means much faster development time and lower maintenance costs, but the resulting program frequently runs faster.

For a fuller discussion of this, see garbage collection.

Explicit Memory Management

Despite D being a garbage collected language, the new and delete operations can be overridden for particular classes so that a custom allocator can be used.

RAII

RAII is a modern software development technique to manage resource allocation and deallocation. D supports RAII in a controlled, predictable manner that is independent of the garbage collection cycle.

Performance

Lightweight Aggregates

D supports simple C style structs, both for compatibility with C data structures and because they're useful when the full power of classes is overkill.

Inline Assembler

Device drivers, high performance system applications, embedded systems, and specialized code sometimes need to dip into assembly language to get the job done. While D implementations are not required to implement the inline assembler, it is defined and part of the language. Most assembly code needs can be handled with it, obviating the need for separate assemblers or DLL's.

Many D implementations will also support intrinsic functions analogously to C's support of intrinsics for I/O port manipulation, direct access to special floating point operations, etc.

Reliability

A modern language should do all it can to help the programmer flush out bugs in the code. Help can come in many forms; from making it easy to use more robust techniques, to compiler flagging of obviously incorrect code, to runtime checking.

Contracts

Contract Programming (invented by B. Meyer) is a revolutionary technique to aid in ensuring the correctness of programs. D's version of DBC includes function preconditions, function postconditions, class invariants, and assert contracts. See Contracts for D's implementation.

Unit Tests

Unit tests can be added to a class, such that they are automatically run upon program startup. This aids in verifying, in every build, that class implementations weren't inadvertently broken. The unit tests form part of the source code for a class. Creating them becomes a natural part of the class development process, as opposed to throwing the finished code over the wall to the testing group.

Unit tests can be done in other languages, but the result is kludgy and the languages just aren't accommodating of the concept. Unit testing is a main feature of D. For library functions it works out great, serving both to guarantee that the functions actually work and to illustrate how to use the functions.

Consider the many C++ library and application code bases out there for download on the web. How much of it comes with *any* verification tests at all, let alone unit testing? Less than 1%? The usual practice is if it compiles, we assume it works. And we wonder if the warnings the compiler spits out in the process are real bugs or just nattering about nits.

Along with Contract Programming, unit testing makes D far and away the best language for writing reliable, robust systems applications. Unit testing also gives us a quick-and-dirty estimate of the quality of some unknown piece of D code dropped in our laps - if it has no unit tests and no contracts, it's unacceptable.

Debug Attributes and Statements

Now debug is part of the syntax of the language. The code can be enabled or disabled at compile time, without the use of macros or preprocessing commands. The debug syntax enables a consistent, portable, and understandable recognition that real source code needs to be able to generate both debug compilations and release compilations.

Exception Handling

The superior try-catch-finally model is used rather than just try-catch. There's no need to create dummy objects just to have the destructor implement the finally semantics.

Synchronization

Multithreaded programming is becoming more and more mainstream, and D provides primitives to build multithreaded programs with. Synchronization can be done at either the method or the object level.

synchronized int func() { ... }

Synchronized functions allow only one thread at a time to be executing that function.

The synchronize statement puts a mutex around a block of statements, controlling access either by object or globally.

Support for Robust Techniques

  • Dynamic arrays instead of pointers
  • Reference variables instead of pointers
  • Reference objects instead of pointers
  • Garbage collection instead of explicit memory management
  • Built-in primitives for thread synchronization
  • No macros to inadvertently slam code
  • Inline functions instead of macros
  • Vastly reduced need for pointers
  • Integral type sizes are explicit
  • No more uncertainty about the signed-ness of chars
  • No need to duplicate declarations in source and header files.
  • Explicit parsing support for adding in debug code.

Compile Time Checks

  • Stronger type checking
  • No empty ; for loop bodies
  • Assignments do not yield boolean results
  • Deprecating of obsolete API's

Runtime Checking

  • assert() expressions
  • array bounds checking
  • undefined case in switch exception
  • out of memory exception
  • In, out, and class invariant Contract Programming support

Compatibility

Operator precedence and evaluation rules

D retains C operators and their precedence rules, order of evaluation rules, and promotion rules. This avoids subtle bugs that might arise from being so used to the way C does things that one has a great deal of trouble finding bugs due to different semantics.

Direct Access to C API's

Not only does D have data types that correspond to C types, it provides direct access to C functions. There is no need to write wrapper functions, parameter swizzlers, nor code to copy aggregate members one by one.

Support for all C data types

Making it possible to interface to any C API or existing C library code. This support includes structs, unions, enums, pointers, and all C99 types. D includes the capability to set the alignment of struct members to ensure compatibility with externally imposed data formats.

OS Exception Handling

D's exception handling mechanism will connect to the way the underlying operating system handles exceptions in an application.

Uses Existing Tools

D produces code in standard object file format, enabling the use of standard assemblers, linkers, debuggers, profilers, exe compressors, and other analyzers, as well as linking to code written in other languages.

Project Management

Versioning

D provides built-in support for generation of multiple versions of a program from the same text. It replaces the C preprocessor #if/#endif technique.

Deprecation

As code evolves over time, some old library code gets replaced with newer, better versions. The old versions must be available to support legacy code, but they can be marked as deprecated. Code that uses deprecated versions will be normally flagged as illegal, but would be allowed by a compiler switch. This will make it easy for maintenance programmers to identify any dependence on deprecated features.

Sample D Program (sieve.d)

/* Sieve of Eratosthenes prime numbers */

import std.stdio;

bool[8191] flags;

int main()
{
    int i, count, prime, k, iter;

    writefln("10 iterations");
    for (iter = 1; iter <= 10; iter++)
    {
        count = 0;
        flags[] = 1;
        for (i = 0; i < flags.length; i++)
        {
            if (flags[i])
            {
                prime = i + i + 3;
                k = i + prime;
                while (k < flags.length)
                {
                    flags[k] = 0;
                    k += prime;
                }
                count += 1;
            }
        }
    }
    writefln("%d primes", count);
    return 0;
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Word Count - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Word Count

This program is the D version of the classic wc (wordcount) C program. It serves to demonstrate how to read files, slice arrays, and simple symbol table management with associative arrays. It has two main code paths, one for smaller files that will fit in memory, and one using buffered file I/O for files that are larger.

import std.stdio;
import std.stream;

int main (string[] args)
{
    int w_total;
    int l_total;
    ulong c_total;
    int[string] dictionary;

    writefln("   lines   words   bytes file");
    foreach (arg; args[1 .. args.length])
    {
        int w_cnt, l_cnt;
        bool inword;

        auto c_cnt = std.file.getSize(arg);
        if (c_cnt < 10_000_000)
        {
            size_t wstart;
            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;
                }
            }
            if (inword)
            {
                auto w = input[wstart .. input.length];
                dictionary[w]++;
            }
        }
        else
        {
            auto f = new BufferedFile(arg);
            string buf;

            while (!f.eof())
            {
                char c;

                f.read(c);
                if (c == '\n')
                ++l_cnt;
                if (c >= '0' && c <= '9')
                {
                    if (inword)
                    buf ~= c;
                }
                else if (c >= 'a' && c <= 'z' ||
                    c >= 'A' && c <= 'Z')
                {
                    if (!inword)
                    {
                        buf.length = 0;
                        buf ~= c;
                        inword = 1;
                        ++w_cnt;
                    }
                    else
                        buf ~= c;
                }
                else if (inword)
                {
                    if (++dictionary[buf] == 1)
                        buf = null;
                    inword = 0;
                }
            }
            if (inword)
            {
                dictionary[buf]++;
            }
        }
        writefln("%8s%8s%8s %s\n", 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;
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Warnings - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Warnings

Depending on one's point of view, warnings are either a symptom of broken language design or a useful ‘lint’ like tool to analyze code and look for potential trouble spots. Most of the time, those trouble spots will be legitimate code intended to be that way. More rarely, it may indicate an unintentional error on the part of the programmer.

Warnings are not a defined part of the D Programming Language. They exist at the discretion of the compiler vendor, and will most likely vary from vendor to vendor. All constructs for which an implementation may generate a warning message are legal D code.

These are the warnings generated by the Digital Mars D compiler when the -w switch is thrown. This mode also forces compiler to stop if any warning is produced. Most have generated some spirited debate as to whether it should be a warning, an error, and what the correct way to write D code in these situations should be. Since no consensus emerged, they appear as optional warnings, with alternatives on how to write correct code.

warning - statement is not reachable

Consider the following code:

int foo(int i)
{
    return i;
    return i + 1;
}

The second return statement is not reachable, i.e. it is dead code. While dead code is poor style in released code, it can legitimately happen a lot when rapidly trying to isolate down a bug or experiment with different bits of code.

The warning can be resolved by:

  1. Commenting out the dead code with /+ ... +/ comments:
    int foo(int i)
{
    return i;
    /+
    return i + 1;
     +/
}
  2. Putting the dead code inside a version(none) conditional:
    int foo(int i)
{
    return i;
    version (none)
    {
    return i + 1;
    }
}
  3. Only compile with warnings enabled when doing release builds.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


D Builtin Rationale - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

D Builtin Rationale

D offers several capabilities built in to the core language that are implemented as libraries in other languages such as C++:

  1. Dynamic Arrays
  2. Strings
  3. Associative Arrays

Some consider this as evidence of language bloat, rather than a useful feature. So why not implement each of these as standardized library types?

Some general initial observations:

  1. Each of them is heavily used. This means that even small improvements in usability are worth reaching for.
  2. Being a core language feature means that the compiler can issue better and more to the point error messages when a type is used incorrectly. Library implementations tend to give notoriously obtuse messages based on the internal details of those implementations.
  3. Library features cannot invent new syntax, new operators, or new tokens.
  4. Library implementations tend to require a lot of compile time processing of the implementation, over and over for each compile, that slows down compilation.
  5. Library implementations are supposed to provide flexibility to the end user. But if they are standardized, to the point of the compiler being allowed to recognize them as special (the C++ Standard allows this), then they become just as inflexible as builtin core features.
  6. The ability to define new library types, while having greatly advanced in the last few years, still leaves a lot to be desired in smoothly integrating it into the existing language. Rough edges, clumsy syntax, and odd corner cases abound.

More specific comments:

Dynamic Arrays

C++ has builtin core arrays. It's just that they don't work very well. Rather than fix them, several different array types were created as part of the C++ Standard Template Library, each covering a different deficiency in the builtin arrays. These include:

  • basic_string
  • vector
  • valarray
  • deque
  • slice_array
  • gslice_array
  • mask_array
  • indirect_array

Fixing the builtin array support means the need for each of these variations just evaporates. There's one array type that covers it all, only one thing to learn, and no problems getting one array type to work with another array type.

As usual, a builtin type lets us create syntactic sugar for it. This starts with having an array literal, and follows with some new operators specific to arrays. A library array implementation has to make due with overloading existing operators. The indexing operator, a[i], it shares with C++. Added are the array concatenation operator ~, array append operator ~=, array slice operator a[i..j], and the array vector operator a[].

The ~ and ~= concatenation operators resolve a problem that comes up when only existing operators can be overloaded. Usually, + is pressed into service as concatenation for library array implementations. But that winds up precluding having + mean array vector addition. Furthermore, concatenation has nothing in common with addition, and using the same operator for both is confusing.

Strings

C++ has, of course, builtin string support in the form of string literals and char arrays. It's just that they suffer from all the weaknesses of C++ builtin arrays.

But after all, what is a string if not an array of characters? If the builtin array problems are fixed, doesn't that resolve the string problems as well? It does. It seems odd at first that D doesn't have a string class, but since manipulating strings is nothing more than manipulating arrays of characters, if arrays work, there's nothing a class adds to it.

Furthermore, the oddities resulting from builtin string literals not being of the same type as the library string class type go away.

Associative Arrays

The main benefit for this is, once again, syntactic sugar. An associative array keying off of a type T and storing an int value is naturally written as:

int[T] foo;

rather than:

import std.associativeArray;
...
std.associativeArray.AA!(T, int) foo;

Builtin associative arrays also offer the possibility of having associative array literals, which are an often requested additional feature.

Please Note

D currently has a built-in complex type that is being phased out in favor of a library implementation. Advances in D language semantics and compiler implementation have obviated the need for a built-in complex type.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Programming in D for C Programmers - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Programming in D for C Programmers

Every experienced C programmer accumulates a series of idioms and techniques which become second nature. Sometimes, when learning a new language, those idioms can be so comfortable it's hard to see how to do the equivalent in the new language. So here's a collection of common C techniques, and how to do the corresponding task in D.

Since C does not have object-oriented features, there's a separate section for object-oriented issues Programming in D for C++ Programmers.

The C preprocessor is covered in The C Preprocessor vs D.

  • Getting the Size of a Type
  • Get the max and min values of a type
  • Primitive Types
  • Special Floating Point Values
  • Remainder after division of floating point numbers
  • Dealing with NANs in floating point compares
  • Asserts
  • Initializing all elements of an array
  • Looping through an array
  • Creating an array of variable size
  • String Concatenation
  • Formatted printing
  • Forward referencing functions
  • Functions that have no arguments
  • Labeled break and continue statements
  • Goto Statements
  • Struct tag name space
  • Looking up strings
  • Setting struct member alignment
  • Anonymous Structs and Unions
  • Declaring struct types and variables
  • Getting the offset of a struct member
  • Union initializations
  • Struct initializations
  • Array initializations
  • Escaped String Literals
  • Ascii vs Wide Characters
  • Arrays that parallel an enum
  • Creating a new type with typedef
  • Comparing structs
  • Comparing strings
  • Sorting arrays
  • Volatile memory access
  • String literals
  • Data Structure Traversal
  • Unsigned Right Shift
  • Dynamic Closures
  • Variadic Function Parameters

Getting the Size of a Type

The C Way

sizeof(int)
sizeof(char *)
sizeof(double)
sizeof(struct Foo)

The D Way

Use the size property:

int.sizeof
(char *).sizeof
double.sizeof
Foo.sizeof

Get the max and min values of a type

The C Way

#include <limits.h>
#include <math.h>

CHAR_MAX
CHAR_MIN
ULONG_MAX
DBL_MIN

The D Way

char.max
char.min
ulong.max
double.min

Primitive Types

C to D types

bool               =>        bit
char               =>        char
signed char        =>        byte
unsigned char      =>        ubyte
short              =>        short
unsigned short     =>        ushort
wchar_t            =>        wchar
int                =>        int
unsigned           =>        uint
long               =>        int
unsigned long      =>        uint
long long          =>        long
unsigned long long =>        ulong
float              =>        float
double             =>        double
long double        =>        real
_Imaginary long double =>    ireal
_Complex long double   =>    creal

Although char is an unsigned 8 bit type, and wchar is an unsigned 16 bit type, they have their own separate types in order to aid overloading and type safety.

Ints and unsigneds in C are of varying size; not so in D.

Special Floating Point Values

The C Way

#include <fp.h>

NAN
INFINITY

#include <float.h>

DBL_DIG
DBL_EPSILON
DBL_MANT_DIG
DBL_MAX_10_EXP
DBL_MAX_EXP
DBL_MIN_10_EXP
DBL_MIN_EXP

The D Way

double.nan
double.infinity
double.dig
double.epsilon
double.mant_dig
double.max_10_exp
double.max_exp
double.min_10_exp
double.min_exp

Remainder after division of floating point numbers

The C Way

#include <math.h>

float f = fmodf(x,y);
double d = fmod(x,y);
long double r = fmodl(x,y);

The D Way

D supports the remainder ('%') operator on floating point operands:
float f = x % y;
double d = x % y;
real r = x % y;

Dealing with NANs in floating point compares

The C Way

C doesn't define what happens if an operand to a compare is NAN, and few C compilers check for it (the Digital Mars C compiler is an exception, DM's compilers do check for NAN operands).
#include <math.h>

if (isnan(x) || isnan(y))
   result = FALSE;
else
   result = (x < y);

The D Way

D offers a full complement of comparisons and operators that work with NAN arguments.
result = (x < y);        // false if x or y is nan

Asserts are a necessary part of any good defensive coding strategy

The C Way

C doesn't directly support assert, but does support __FILE__ and __LINE__ from which an assert macro can be built. In fact, there appears to be practically no other use for __FILE__ and __LINE__.

#include <assert.h>

assert(e == 0);

The D Way

D simply builds assert into the language:
assert(e == 0);

Initializing all elements of an array

The C Way

#define ARRAY_LENGTH        17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
   array[i] = value;

The D Way

int array[17];
array[] = value;

Looping through an array

The C Way

The array length is defined separately, or a clumsy sizeof() expression is used to get the length.

#define ARRAY_LENGTH        17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
   func(array[i]);
or:
int array[17];
for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
   func(array[i]);

The D Way

The length of an array is accessible through the property "length".
int array[17];
for (i = 0; i < array.length; i++)
   func(array[i]);
or even better:
int array[17];
foreach (int value; array)
   func(value);

Creating an array of variable size

The C Way

C cannot do this with arrays. It is necessary to create a separate variable for the length, and then explicitly manage the size of the array:
#include <stdlib.h>

int array_length;
int *array;
int *newarray;

newarray = (int *)
   realloc(array, (array_length + 1) * sizeof(int));
if (!newarray)
   error("out of memory");
array = newarray;
array[array_length++] = x;

The D Way

D supports dynamic arrays, which can be easily resized. D supports all the requisite memory management.
int[] array;

array.length = array.length + 1;
array[array.length - 1] = x;

String Concatenation

The C Way

There are several difficulties to be resolved, like when can storage be freed, dealing with null pointers, finding the length of the strings, and memory allocation:
#include <string.h>

char *s1;
char *s2;
char *s;

// Concatenate s1 and s2, and put result in s
free(s);
s = (char *)malloc((s1 ? strlen(s1) : 0) +
          (s2 ? strlen(s2) : 0) + 1);
if (!s)
   error("out of memory");
if (s1)
   strcpy(s, s1);
else
   *s = 0;
if (s2)
   strcpy(s + strlen(s), s2);

// Append "hello" to s
char hello[] = "hello";
char *news;
size_t lens = s ? strlen(s) : 0;
news = (char *)
   realloc(s, (lens + sizeof(hello) + 1) * sizeof(char));
if (!news)
   error("out of memory");
s = news;
memcpy(s + lens, hello, sizeof(hello));

The D Way

D overloads the operators ~ and ~= for char and wchar arrays to mean concatenate and append, respectively:
char[] s1;
char[] s2;
char[] s;

s = s1 ~ s2;
s ~= "hello";

Formatted printing

The C Way

printf() is the general purpose formatted print routine:
#include <stdio.h>

printf("Calling all cars %d times!\n", ntimes);

The D Way

What can we say? printf() rules:
printf("Calling all cars %d times!\n", ntimes);
writefln() improves on printf() by being type-aware and type-safe:
import std.stdio;

writefln("Calling all cars %s times!", ntimes);

Forward referencing functions

The C Way

Functions cannot be forward referenced. Hence, to call a function not yet encountered in the source file, it is necessary to insert a function declaration lexically preceding the call.
void forwardfunc();

void myfunc()
{
   forwardfunc();
}

void forwardfunc()
{
   ...
}

The D Way

The program is looked at as a whole, and so not only is it not necessary to code forward declarations, it is not even allowed! D avoids the tedium and errors associated with writing forward referenced function declarations twice. Functions can be defined in any order.
void myfunc()
{
   forwardfunc();
}

void forwardfunc()
{
   ...
}

Functions that have no arguments

The C Way

void function(void);

The D Way

D is a strongly typed language, so there is no need to explicitly say a function takes no arguments, just don't declare it has having arguments.
void function()
{
   ...
}

Labeled break and continue statements

The C Way

Break and continue statements only apply to the innermost nested loop or switch, so a multilevel break must use a goto:
   for (i = 0; i < 10; i++)
    {
       for (j = 0; j < 10; j++)
       {
       if (j == 3)
           goto Louter;
       if (j == 4)
           goto L2;
       }
     L2:
       ;
    }
Louter:
    ;

The D Way

Break and continue statements can be followed by a label. The label is the label for an enclosing loop or switch, and the break applies to that loop.
Louter:
   for (i = 0; i < 10; i++)
   {
       for (j = 0; j < 10; j++)
       {
       if (j == 3)
           break Louter;
       if (j == 4)
           continue Louter;
       }
   }
   // break Louter goes here

Goto Statements

The C Way

The much maligned goto statement is a staple for professional C coders. It's necessary to make up for sometimes inadequate control flow statements.

The D Way

Many C-way goto statements can be eliminated with the D feature of labeled break and continue statements. But D is a practical language for practical programmers who know when the rules need to be broken. So of course D supports goto statements.

Struct tag name space

The C Way

It's annoying to have to put the struct keyword every time a type is specified, so a common idiom is to use:
typedef struct ABC { ... } ABC;

The D Way

Struct tag names are not in a separate name space, they are in the same name space as ordinary names. Hence:
struct ABC { ... }

Looking up strings

The C Way

Given a string, compare the string against a list of possible values and take action based on which one it is. A typical use for this might be command line argument processing.
#include <string.h>
void dostring(char *s)
{
   enum Strings { Hello, Goodbye, Maybe, Max };
   static char *table[] = { "hello", "goodbye", "maybe" };
   int i;

   for (i = 0; i < Max; i++)
   {
       if (strcmp(s, table[i]) == 0)
       break;
   }
   switch (i)
   {
       case Hello:   ...
       case Goodbye: ...
       case Maybe:   ...
       default:      ...
   }
}
The problem with this is trying to maintain 3 parallel data structures, the enum, the table, and the switch cases. If there are a lot of values, the connection between the 3 may not be so obvious when doing maintenance, and so the situation is ripe for bugs. Additionally, if the number of values becomes large, a binary or hash lookup will yield a considerable performance increase over a simple linear search. But coding these can be time consuming, and they need to be debugged. It's typical that such just never gets done.

The D Way

D extends the concept of switch statements to be able to handle strings as well as numbers. Then, the way to code the string lookup becomes straightforward:
void dostring(char[] s)
{
   switch (s)
   {
       case "hello":   ...
       case "goodbye": ...
       case "maybe":   ...
       default:        ...
   }
}
Adding new cases becomes easy. The compiler can be relied on to generate a fast lookup scheme for it, eliminating the bugs and time required in hand-coding one.

Setting struct member alignment

The C Way

It's done through a command line switch which affects the entire program, and woe results if any modules or libraries didn't get recompiled. To address this, #pragmas are used:
#pragma pack(1)
struct ABC
{
   ...
};
#pragma pack()
But #pragmas are nonportable both in theory and in practice from compiler to compiler.

The D Way

D has a syntax for setting the alignment that is common to all D compilers. The actual alignment done is compatible with the companion C compiler's alignment, for ABI compatibility. To match a particular layout across architectures, use align(1) and manually specify it.

struct ABC
{
   int z;               // z is aligned to the default

 align (1) int x;       // x is byte aligned
 align (4)
 {
   ...                  // declarations in {} are dword aligned
 }
 align (2):             // switch to word alignment from here on

   int y;               // y is word aligned
}

Anonymous Structs and Unions

Sometimes, it's nice to control the layout of a struct with nested structs and unions.

The C Way

C doesn't allow anonymous structs or unions, which means that dummy tag names and dummy members are necessary:
struct Foo
{
   int i;
   union Bar
   {
      struct Abc { int x; long y; } _abc;
      char *p;
   } _bar;
};

#define x _bar._abc.x
#define y _bar._abc.y
#define p _bar.p

struct Foo f;

f.i;
f.x;
f.y;
f.p;
Not only is it clumsy, but using macros means a symbolic debugger won't understand what is being done, and the macros have global scope instead of struct scope.

The D Way

Anonymous structs and unions are used to control the layout in a more natural manner:
struct Foo
{
   int i;
   union
   {
      struct { int x; long y; }
      char* p;
   }
}

Foo f;

f.i;
f.x;
f.y;
f.p;

Declaring struct types and variables

The C Way

Is to do it in one statement ending with a semicolon:

struct Foo { int x; int y; } foo;

Or to separate the two:

struct Foo { int x; int y; };   // note terminating ;
struct Foo foo;

The D Way

Struct definitions and declarations can't be done in the same statement:

struct Foo { int x; int y; }    // note there is no terminating ;
Foo foo;

which means that the terminating ; can be dispensed with, eliminating the confusing difference between struct {} and function block {} in how semicolons are used.

Getting the offset of a struct member

The C Way

Naturally, another macro is used:
#include <stddef>
struct Foo { int x; int y; };

off = offsetof(Foo, y);

The D Way

An offset is just another property:
struct Foo { int x; int y; }

off = Foo.y.offsetof;

Union Initializations

The C Way

Unions are initialized using the "first member" rule:
union U { int a; long b; };
union U x = { 5 };                // initialize member 'a' to 5
Adding union members or rearranging them can have disastrous consequences for any initializers.

The D Way

In D, which member is being initialized is mentioned explicitly:
union U { int a; long b; }
U x = { a:5 };
avoiding the confusion and maintenance problems.

Struct Initializations

The C Way

Members are initialized by their position within the { }s:
struct S { int a; int b; };
struct S x = { 5, 3 };
This isn't much of a problem with small structs, but when there are numerous members, it becomes tedious to get the initializers carefully lined up with the field declarations. Then, if members are added or rearranged, all the initializations have to be found and modified appropriately. This is a minefield for bugs.

The D Way

Member initialization can be done explicitly:
struct S { int a; int b; }
S x = { b:3, a:5 };
The meaning is clear, and there no longer is a positional dependence.

Array Initializations

The C Way

C initializes array by positional dependence:
int a[3] = { 3,2,2 };
Nested arrays may or may not have the { }:
int b[3][2] = { 2,3, {6,5}, 3,4 };

The D Way

D does it by positional dependence too, but an index can be used as well. The following all produce the same result:
int[3] a = [ 3, 2, 0 ];
int[3] a = [ 3, 2 ];            // unsupplied initializers are 0, just like in C
int[3] a = [ 2:0, 0:3, 1:2 ];
int[3] a = [ 2:0, 0:3, 2 ];     // if not supplied, the index is the
                // previous one plus one.
This can be handy if the array will be indexed by an enum, and the order of enums may be changed or added to:
enum color { black, red, green }
int[3] c = [ black:3, green:2, red:5 ];
Nested array initializations must be explicit:
int[2][3] b = [ [2,3], [6,5], [3,4] ];

int[2][3] b = [[2,6,3],[3,5,4]];            // error

Escaped String Literals

The C Way

C has problems with the DOS file system because a \ is an escape in a string. To specifiy file c:\root\file.c:
char file[] = "c:\\root\\file.c";
This gets even more unpleasant with regular expressions. Consider the escape sequence to match a quoted string:
/"[^\\]*(\\.[^\\]*)*"/

In C, this horror is expressed as:

char quoteString[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\"";

The D Way

Within strings, it is WYSIWYG (what you see is what you get). Escapes are in separate strings. So:
char[] file = `c:\root\file.c`;
char[] quoteString = \"  r"[^\\]*(\\.[^\\]*)*"  \";
The famous hello world string becomes:
char[] hello = "hello world" \n;

Ascii vs Wide Characters

Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs.

The C Way

C uses the wchar_t and the L prefix on strings:
#include <wchar.h>
char foo_ascii[] = "hello";
wchar_t foo_wchar[] = L"hello";
Things get worse if code is written to be both ascii and wchar compatible. A macro is used to switch strings from ascii to wchar:
#include <tchar.h>
tchar string[] = TEXT("hello");

The D Way

The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call:
char[] foo_ascii = "hello";        // string is taken to be ascii
wchar[] foo_wchar = "hello";       // string is taken to be wchar

Arrays that parallel an enum

The C Way

Consider:
enum COLORS { red, blue, green, max };
char *cstring[max] = {"red", "blue", "green" };
This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added.

The D Way

enum COLORS { red, blue, green }

char[][COLORS.max + 1] cstring =
[
    COLORS.red   : "red",
    COLORS.blue  : "blue",
    COLORS.green : "green",
];
Not perfect, but better.

Creating a new type with typedef

The C Way

Typedefs in C are weak, that is, they really do not introduce a new type. The compiler doesn't distinguish between a typedef and its underlying type.
typedef void *Handle;
void foo(void *);
void bar(Handle);

Handle h;
foo(h);			// coding bug not caught
bar(h);			// ok
The C solution is to create a dummy struct whose sole purpose is to get type checking and overloading on the new type.
struct Handle__ { void *value; }
typedef struct Handle__ *Handle;
void foo(void *);
void bar(Handle);

Handle h;
foo(h);			// syntax error
bar(h);			// ok
Having a default value for the type involves defining a macro, a naming convention, and then pedantically following that convention:
#define HANDLE_INIT ((Handle)-1)

Handle h = HANDLE_INIT;
h = func();
if (h != HANDLE_INIT)
    ...
For the struct solution, things get even more complex:
struct Handle__ HANDLE_INIT;

void init_handle()	// call this function upon startup
{
    HANDLE_INIT.value = (void *)-1;
}

Handle h = HANDLE_INIT;
h = func();
if (memcmp(&h,&HANDLE_INIT,sizeof(Handle)) != 0)
    ...
There are 4 names to remember: Handle, HANDLE_INIT, struct Handle__, value.

The D Way

No need for idiomatic constructions like the above. Just write:
typedef void* Handle;
void foo(void*);
void bar(Handle);

Handle h;
foo(h);
bar(h);
To handle a default value, add an initializer to the typedef, and refer to it with the .init property:
typedef void* Handle = cast(void*)(-1);
Handle h;
h = func();
if (h != Handle.init)
    ...
There's only one name to remember: Handle.

Comparing structs

The C Way

While C defines struct assignment in a simple, convenient manner:
struct A x, y;
...
x = y;
it does not for struct comparisons. Hence, to compare two struct instances for equality:
#include <string.h>

struct A x, y;
...
if (memcmp(&x, &y, sizeof(struct A)) == 0)
    ...
Note the obtuseness of this, coupled with the lack of any kind of help from the language with type checking.

There's a nasty bug lurking in the memcmp(). The layout of a struct, due to alignment, can have 'holes' in it. C does not guarantee those holes are assigned any values, and so two different struct instances can have the same value for each member, but compare different because the holes contain different garbage.

The D Way

D does it the obvious, straightforward way:
A x, y;
...
if (x == y)
    ...

Comparing strings

The C Way

The library function strcmp() is used:
char string[] = "hello";

if (strcmp(string, "betty") == 0)	// do strings match?
    ...
C uses 0 terminated strings, so the C way has an inherent inefficiency in constantly scanning for the terminating 0.

The D Way

Why not use the == operator?
char[] string = "hello";

if (string == "betty")
    ...
D strings have the length stored separately from the string. Thus, the implementation of string compares can be much faster than in C (the difference being equivalent to the difference in speed between the C memcmp() and strcmp()).

D supports comparison operators on strings, too:

char[] string = "hello";

if (string < "betty")
    ...
which is useful for sorting/searching.

Sorting arrays

The C Way

Although many C programmers tend to reimplmement bubble sorts over and over, the right way to sort in C is to use qsort():
int compare(const void *p1, const void *p2)
{
    type *t1 = (type *)p1;
    type *t2 = (type *)p2;

    return *t1 - *t2;
}

type array[10];
...
qsort(array, sizeof(array)/sizeof(array[0]),
    sizeof(array[0]), compare);
A compare() must be written for each type, and much careful typo-prone code needs to be written to make it work.

The D Way

Sorting couldn't be easier:
type[] array;
...
array.sort;      // sort array in-place

Volatile memory access

The C Way

To access volatile memory, such as shared memory or memory mapped I/O, a pointer to volatile is created:
volatile int *p = address;

i = *p;

The D Way

D has volatile as a statement type, not as a type modifier:
int* p = address;

volatile { i = *p; }

String literals

The C Way

String literals in C cannot span multiple lines, so to have a block of text it is necessary to use \ line splicing:
"This text spans\n\
multiple\n\
lines\n"
If there is a lot of text, this can wind up being tedious.

The D Way

String literals can span multiple lines, as in:
"This text spans
multiple
lines
"
So blocks of text can just be cut and pasted into the D source.

Data Structure Traversal

The C Way

Consider a function to traverse a recursive data structure. In this example, there's a simple symbol table of strings. The data structure is an array of binary trees. The code needs to do an exhaustive search of it to find a particular string in it, and determine if it is a unique instance.

To make this work, a helper function membersearchx is needed to recursively walk the trees. The helper function needs to read and write some context outside of the trees, so a custom struct Paramblock is created and a pointer to it is used to maximize efficiency.

struct Symbol
{
   char *id;
   struct Symbol *left;
   struct Symbol *right;
};

struct Paramblock
{
   char *id;
   struct Symbol *sm;
};

static void membersearchx(struct Paramblock *p, struct Symbol *s)
{
   while (s)
   {
      if (strcmp(p->id,s->id) == 0)
      {
         if (p->sm)
            error("ambiguous member %s\n",p->id);
         p->sm = s;
      }

      if (s->left)
         membersearchx(p,s->left);
      s = s->right;
   }
}

struct Symbol *symbol_membersearch(Symbol *table[], int tablemax, char *id)
{
   struct Paramblock pb;
   int i;

   pb.id = id;
   pb.sm = NULL;
   for (i = 0; i < tablemax; i++)
   {
      membersearchx(pb, table[i]);
   }
   return pb.sm;
}

The D Way

This is the same algorithm in D, and it shrinks dramatically. Since nested functions have access to the lexically enclosing function's variables, there's no need for a Paramblock or to deal with its bookkeeping details. The nested helper function is contained wholly within the function that needs it, improving locality and maintainability.

The performance of the two versions is indistinguishable.

class Symbol
{   char[] id;
    Symbol left;
    Symbol right;
}

Symbol symbol_membersearch(Symbol[] table, char[] id)
{   Symbol sm;

    void membersearchx(Symbol s)
    {
    while (s)
    {
        if (id == s.id)
        {
        if (sm)
            error("ambiguous member %s\n", id);
        sm = s;
        }

        if (s.left)
        membersearchx(s.left);
        s = s.right;
    }
    }

    for (int i = 0; i < table.length; i++)
    {
    membersearchx(table[i]);
    }
    return sm;
}

Unsigned Right Shift

The C Way

The right shift operators >> and >>= are signed shifts if the left operand is a signed integral type, and are unsigned right shifts if the left operand is an unsigned integral type. To produce an unsigned right shift on an int, a cast is necessary:
int i, j;
...
j = (unsigned)i >> 3;
If i is an int, this works fine. But if i is of a type created with typedef,
myint i, j;
...
j = (unsigned)i >> 3;
and myint happens to be a long int, then the cast to unsigned will silently throw away the most significant bits, corrupting the answer.

The D Way

D has the right shift operators >> and >>= which behave as they do in C. But D also has explicitly unsigned right shift operators >>> and >>>= which will do an unsigned right shift regardless of the sign of the left operand. Hence,
myint i, j;
...
j = i >>> 3;
avoids the unsafe cast and will work as expected with any integral type.

Dynamic Closures

The C Way

Consider a reusable container type. In order to be reusable, it must support a way to apply arbitrary code to each element of the container. This is done by creating an apply function that accepts a function pointer to which is passed each element of the container contents.

A generic context pointer is also needed, represented here by void *p. The example here is of a trivial container class that holds an array of ints, and a user of that container that computes the maximum of those ints.

void apply(void *p, int *array, int dim, void (*fp)(void *, int))
{
    for (int i = 0; i < dim; i++)
    fp(p, array[i]);
}

struct Collection
{
    int array[10];
};

void comp_max(void *p, int i)
{
    int *pmax = (int *)p;

    if (i > *pmax)
    *pmax = i;
}

void func(struct Collection *c)
{
    int max = INT_MIN;

    apply(&max, c->array, sizeof(c->array)/sizeof(c->array[0]), comp_max);
}

While this works, it isn't very flexible.

The D Way

The D version makes use of delegates to transmit context information for the apply function, and nested functions both to capture context information and to improve locality.
class Collection
{
    int[10] array;

    void apply(void delegate(int) fp)
    {
    for (int i = 0; i < array.length; i++)
        fp(array[i]);
    }
}

void func(Collection c)
{
    int max = int.min;

    void comp_max(int i)
    {
    if (i > max)
        max = i;
    }

    c.apply(&amp;comp_max);
}
Pointers are eliminated, as well as casting and generic pointers. The D version is fully type safe. An alternate method in D makes use of function literals:
void func(Collection c)
{
    int max = int.min;

    c.apply(delegate(int i) { if (i > max) max = i; } );
}
eliminating the need to create irrelevant function names.

Variadic Function Parameters

The task is to write a function that takes a varying number of arguments, such as a function that sums its arguments.

The C Way

#include <stdio.h>
#include <stdarg.h>

int sum(int dim, ...)
{   int i;
    int s = 0;
    va_list ap;

    va_start(ap, dim);
    for (i = 0; i < dim; i++)
    s += va_arg(ap, int);
    va_end(ap);
    return s;
}

int main()
{
    int i;

    i = sum(3, 8,7,6);
    printf("sum = %d\n", i);

    return 0;
}
There are two problems with this. The first is that the sum function needs to know how many arguments were supplied. It has to be explicitly written, and it can get out of sync with respect to the actual number of arguments written. The second is that there's no way to check that the types of the arguments provided really were ints, and not doubles, strings, structs, etc.

The D Way

The ... following an array parameter declaration means that the trailing arguments are collected together to form an array. The arguments are type checked against the array type, and the number of arguments becomes a property of the array:
import std.stdio;

int sum(int[] values ...)
{
    int s = 0;

    foreach (int x; values)
    s += x;
    return s;
}

int main()
{
    int i;

    i = sum(8,7,6);
    writefln("sum = %d", i);

    return 0;
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Programming in D for C++ Programmers - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Programming in D for C++ Programmers

Every experienced C++ programmer accumulates a series of idioms and techniques which become second nature. Sometimes, when learning a new language, those idioms can be so comfortable it's hard to see how to do the equivalent in the new language. So here's a collection of common C++ techniques, and how to do the corresponding task in D.

See also: Programming in D for C Programmers

  • Defining Constructors
  • Base class initialization
  • Comparing structs
  • Creating a new typedef'd type
  • Friends
  • Operator overloading
  • Namespace using declarations
  • RAII (Resource Acquisition Is Initialization)
  • Properties
  • Recursive Templates
  • Meta Templates
  • Type Traits

Defining constructors

The C++ Way

Constructors have the same name as the class:
class Foo
{
    Foo(int x);
};

The D Way

Constructors are defined with the this keyword:
class Foo
{
    this(int x) { }
}
which reflects how they are used in D.

Base class initialization

The C++ Way

Base constructors are called using the base initializer syntax.
class A { A() {... } };
class B : A
{
     B(int x)
    : A()		// call base constructor
     {	...
     }
};

The D Way

The base class constructor is called with the super syntax:
class A { this() { ... } }
class B : A
{
     this(int x)
     {	...
    super();	// call base constructor
    ...
     }
}
It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived constructor. D can also have one constructor call another one:
class A
{	int a;
    int b;
    this() { a = 7; b = foo(); }
    this(int x)
    {
        this();
        a = x;
    }
}
Members can also be initialized to constants before the constructor is ever called, so the above example is equivalently written as:
class A
{	int a = 7;
    int b;
    this() { b = foo(); }
    this(int x)
    {
        this();
        a = x;
    }
}

Comparing structs

The C++ Way

While C++ defines struct assignment in a simple, convenient manner:
struct A x, y;
...
x = y;
it does not for struct comparisons. Hence, to compare two struct instances for equality:
#include <string.h>

struct A x, y;

inline bool operator==(const A& x, const A& y)
{
    return (memcmp(&x, &y, sizeof(struct A)) == 0);
}
...
if (x == y)
    ...
Note that the operator overload must be done for every struct needing to be compared, and the implementation of that overloaded operator is free of any language help with type checking. The C++ way has an additional problem in that just inspecting the (x == y) does not give a clue what is actually happening, you have to go and find the particular overloaded operator==() that applies to verify what it really does.

There's a nasty bug lurking in the memcmp() implementation of operator==(). The layout of a struct, due to alignment, can have ‘holes’ in it. C++ does not guarantee those holes are assigned any values, and so two different struct instances can have the same value for each member, but compare different because the holes contain different garbage.

To address this, the operator==() can be implemented to do a memberwise compare. Unfortunately, this is unreliable because (1) if a member is added to the struct definition one may forget to add it to operator==(), and (2) floating point nan values compare unequal even if their bit patterns match.

There just is no robust solution in C++.

The D Way

D does it the obvious, straightforward way:
A x, y;
...
if (x == y)
    ...

Creating a new typedef'd type

The C++ Way

Typedef's in C++ are weak, that is, they really do not introduce a new type. The compiler doesn't distinguish between a typedef and its underlying type.
#define HANDLE_INIT	((Handle)(-1))
typedef void *Handle;
void foo(void *);
void bar(Handle);

Handle h = HANDLE_INIT;
foo(h);			// coding bug not caught
bar(h);			// ok
The C++ solution is to create a dummy struct whose sole purpose is to get type checking and overloading on the new type.
#define HANDLE_INIT	((void *)(-1))
struct Handle
{   void *ptr;

    // default initializer
    Handle() { ptr = HANDLE_INIT; }

    Handle(int i) { ptr = (void *)i; }

    // conversion to underlying type
    operator void*() { return ptr; }
};
void bar(Handle);

Handle h;
bar(h);
h = func();
if (h != HANDLE_INIT)
    ...

The D Way

No need for idiomatic constructions like the above. Just write:
typedef void* Handle = cast(void*)-1;
void bar(Handle);

Handle h;
bar(h);
h = func();
if (h != Handle.init)
    ...
Note how a default initializer can be supplied for the typedef as a value of the underlying type.

Friends

The C++ Way

Sometimes two classes are tightly related but not by inheritance, but need to access each other's private members. This is done using friend declarations:
class A
{
    private:
    int a;

    public:
    int foo(B *j);
    friend class B;
    friend int abc(A *);
};

class B
{
    private:
    int b;

    public:
    int bar(A *j);
    friend class A;
};

int A::foo(B *j) { return j->b; }
int B::bar(A *j) { return j->a; }

int abc(A *p) { return p->a; }

The D Way

In D, friend access is implicit in being a member of the same module. It makes sense that tightly related classes should be in the same module, so implicitly granting friend access to other module members solves the problem neatly:
module X;

class A
{
    private:
    static int a;

    public:
    int foo(B j) { return j.b; }
}

class B
{
    private:
    static int b;

    public:
    int bar(A j) { return j.a; }
}

int abc(A p) { return p.a; }
The private attribute prevents other modules from accessing the members.

Operator overloading

The C++ Way

Given a struct that creates a new arithmetic data type, it's convenient to overload the comparison operators so it can be compared against integers:
struct A
{
    int operator <  (int i);
    int operator <= (int i);
    int operator >  (int i);
    int operator >= (int i);
};

int operator <  (int i, A &a) { return a >  i; }
int operator <= (int i, A &a) { return a >= i; }
int operator >  (int i, A &a) { return a <  i; }
int operator >= (int i, A &a) { return a <= i; }
A total of 8 functions are necessary.

The D Way

D recognizes that the comparison operators are all fundamentally related to each other. So only one function is necessary:
struct A
{
    int opCmp(int i);
}
The compiler automatically interprets all the <, <=, > and >= operators in terms of the cmp function, as well as handling the cases where the left operand is not an object reference.

Similar sensible rules hold for other operator overloads, making using operator overloading in D much less tedious and less error prone. Far less code needs to be written to accomplish the same effect.

Namespace using declarations

The C++ Way

A using-declaration in C++ is used to bring a name from a namespace scope into the current scope:
namespace foo
{
    int x;
}
using foo::x;

The D Way

D uses modules instead of namespaces and #include files, and alias declarations take the place of using declarations:
/** Module foo.d **/
module foo;
int x;

/** Another module **/
import foo;
alias foo.x x;
Alias is a much more flexible than the single purpose using declaration. Alias can be used to rename symbols, refer to template members, refer to nested class types, etc.

RAII (Resource Acquisition Is Initialization)

The C++ Way

In C++, resources like memory, etc., all need to be handled explicitly. Since destructors automatically get called when leaving a scope, RAII is implemented by putting the resource release code into the destructor:
class File
{   Handle *h;

    ~File()
    {
    h->release();
    }
};

The D Way

The bulk of resource release problems are simply keeping track of and freeing memory. This is handled automatically in D by the garbage collector. The second common resources used are semaphores and locks, handled automatically with D's synchronized declarations and statements.

The few RAII issues left are handled by scope classes. Scope classes get their destructors run when they go out of scope.

scope class File
{   Handle h;

    ~this()
    {
    h.release();
    }
}

void test()
{
    if (...)
    {   scope f = new File();
    ...
    } // f.~this() gets run at closing brace, even if
      // scope was exited via a thrown exception
}

Properties

The C++ Way

It is common practice to define a field, along with object-oriented get and set functions for it:
class Abc
{
  public:
    void setProperty(int newproperty) { property = newproperty; }
    int getProperty() { return property; }

  private:
    int property;
};

Abc a;
a.setProperty(3);
int x = a.getProperty();
All this is quite a bit of typing, and it tends to make code unreadable by filling it with getProperty() and setProperty() calls.

The D Way

Properties can be get and set using the normal field syntax, yet the get and set will invoke methods instead.
class Abc
{
    // set
    @property void property(int newproperty) { myprop = newproperty; }

    // get
    @property int property() { return myprop; }

  private:
    int myprop;
}
which is used as:
Abc a = new Abc;
a.property = 3;
int x = a.property;
Thus, in D a property is treated like it was a simple field name. A property can start out actually being a simple field name, but if later it becomes necessary to make getting and setting it function calls, no code needs to be modified other than the class definition. It obviates the wordy practice of defining get and set properties ‘just in case’ a derived class should need to override them. It's also a way to have interface classes, which do not have data fields, behave syntactically as if they did.

Recursive Templates

The C++ Way

An advanced use of templates is to recursively expand them, relying on specialization to end it. A template to compute a factorial would be:
template<int n> class factorial
{
    public:
    enum { result = n * factorial<n - 1>::result };
};

template<> class factorial<1>
{
    public:
    enum { result = 1 };
};

void test()
{
    printf("%d\n", factorial<4>::result); // prints 24
}

The D Way

The D version is analogous, though a little simpler, taking advantage of promotion of single template members to the enclosing name space:
template factorial(int n)
{
    enum { factorial = n * .factorial!(n-1) }
}

template factorial(int n : 1)
{
    enum { factorial = 1 }
}

void test()
{
    writefln("%d", factorial!(4));	// prints 24
}

Meta Templates

The problem: create a typedef for a signed integral type that is at least nbits in size.

The C++ Way

This example is simplified and adapted from one written by Dr. Carlo Pescio in Template Metaprogramming: Make parameterized integers portable with this novel technique.

There is no way in C++ to do conditional compilation based on the result of an expression based on template parameters, so all control flow follows from pattern matching of the template argument against various explicit template specializations. Even worse, there is no way to do template specializations based on relationships like "less than or equal to", so the example uses a clever technique where the template is recursively expanded, incrementing the template value argument by one each time, until a specialization matches. If there is no match, the result is an unhelpful recursive compiler stack overflow or internal error, or at best a strange syntax error.

A preprocessor macro is also needed to make up for the lack of template typedefs.

#include <limits.h>

template< int nbits > struct Integer
{
    typedef Integer< nbits + 1 > :: int_type int_type ;
} ;

struct Integer< 8 >
{
    typedef signed char int_type ;
} ;

struct Integer< 16 >
{
    typedef short int_type ;
} ;

struct Integer< 32 >
{
    typedef int int_type ;
} ;

struct Integer< 64 >
{
    typedef long long int_type ;
} ;

// If the required size is not supported, the metaprogram
// will increase the counter until an internal error is
// signaled, or INT_MAX is reached. The INT_MAX
// specialization does not define a int_type, so a
// compiling error is always generated
struct Integer< INT_MAX >
{
} ;

// A bit of syntactic sugar
#define Integer( nbits ) Integer< nbits > :: int_type

#include <stdio.h>

int main()
{
    Integer( 8 ) i ;
    Integer( 16 ) j ;
    Integer( 29 ) k ;
    Integer( 64 ) l ;
    printf("%d %d %d %d\n",
    sizeof(i), sizeof(j), sizeof(k), sizeof(l));
    return 0 ;
}

The C++ Boost Way

This version uses the C++ Boost library. It was provided by David Abrahams.
#include <boost/mpl/if.hpp>
#include <boost/mpl/assert.hpp>

template <int nbits> struct Integer
    : mpl::if_c<(nbits <= 8), signed char
    , mpl::if_c<(nbits <= 16), short
    , mpl::if_c<(nbits <= 32), long
    , long long>::type >::type >
{
    BOOST_MPL_ASSERT_RELATION(nbits, <=, 64);
}

#include <stdio.h>

int main()
{
    Integer< 8 > i ;
    Integer< 16 > j ;
    Integer< 29 > k ;
    Integer< 64 > l ;
    printf("%d %d %d %d\n",
    sizeof(i), sizeof(j), sizeof(k), sizeof(l));
    return 0 ;
}

The D Way

The D version could also be written with recursive templates, but there's a better way. Unlike the C++ example, this one is fairly easy to figure out what is going on. It compiles quickly, and gives a sensible compile time message if it fails.
import std.stdio;

template Integer(int nbits)
{
    static if (nbits <= 8)
    alias byte Integer;
    else static if (nbits <= 16)
    alias short Integer;
    else static if (nbits <= 32)
    alias int Integer;
    else static if (nbits <= 64)
    alias long Integer;
    else
    static assert(0);
}

int main()
{
    Integer!(8) i ;
    Integer!(16) j ;
    Integer!(29) k ;
    Integer!(64) l ;
    writefln("%d %d %d %d",
    i.sizeof, j.sizeof, k.sizeof, l.sizeof);
    return 0;
}

Type Traits

Type traits are another term for being able to find out properties of a type at compile time.

The C++ Way

The following template comes from C++ Templates: The Complete Guide, David Vandevoorde, Nicolai M. Josuttis pg. 353 which determines if the template's argument type is a function:
template<typename T> class IsFunctionT
{
    private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template<typename U> static One test(...);
    template<typename U> static Two test(U (*)[1]);
    public:
    enum { Yes = sizeof(IsFunctionT<T>::test<T>(0)) == 1 };
};

void test()
{
    typedef int (fp)(int);

    assert(IsFunctionT<fp>::Yes == 1);
}
This template relies on the SFINAE (Substitution Failure Is Not An Error) principle. Why it works is a fairly advanced template topic.

The D Way

SFINAE (Substitution Failure Is Not An Error) can be done in D without resorting to template argument pattern matching:
template IsFunctionT(T)
{
    static if ( is(T[]) )
    const int IsFunctionT = 0;
    else
    const int IsFunctionT = 1;
}

void test()
{
    typedef int fp(int);

    assert(IsFunctionT!(fp) == 1);
}
The task of discovering if a type is a function doesn't need a template at all, nor does it need the subterfuge of attempting to create the invalid array of functions type. The IsExpression expression can test it directly:
void test()
{
    alias int fp(int);

    assert( is(fp == function) );
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


The C Preprocessor vs D - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

The C Preprocessor vs D

Back when C was invented, compiler technology was primitive. Installing a text macro preprocessor onto the front end was a straightforward and easy way to add many powerful features. The increasing size & complexity of programs have illustrated that these features come with many inherent problems. D doesn't have a preprocessor; but D provides a more scalable means to solve the same problems.

  • Header Files
  • #pragma once
  • #pragma pack
  • Macros
  • Conditional Compilation
  • Code Factoring
  • #error and Static Asserts
  • Template Mixins

Header Files

The C Preprocessor Way

C and C++ rely heavily on textual inclusion of header files. This frequently results in the compiler having to recompile tens of thousands of lines of code over and over again for every source file, an obvious source of slow compile times. What header files are normally used for is more appropriately done doing a symbolic, rather than textual, insertion. This is done with the import statement. Symbolic inclusion means the compiler just loads an already compiled symbol table. The needs for macro "wrappers" to prevent multiple #inclusion, funky #pragma once syntax, and incomprehensible fragile syntax for precompiled headers are simply unnecessary and irrelevant to D.

#include <stdio.h>

The D Way

D uses symbolic imports:

import std.c.stdio;

#pragma once

The C Preprocessor Way

C header files frequently need to be protected against being #include'd multiple times. To do it, a header file will contain the line:

#pragma once

or the more portable:

#ifndef __STDIO_INCLUDE
#define __STDIO_INCLUDE
... header file contents
#endif

The D Way

Completely unnecessary since D does a symbolic include of import files; they only get imported once no matter how many times the import declaration appears.

#pragma pack

The C Preprocessor Way

This is used in C to adjust the alignment for structs.

The D Way

For D classes, there is no need to adjust the alignment (in fact, the compiler is free to rearrange the data fields to get the optimum layout, much as the compiler will rearrange local variables on the stack frame). For D structs that get mapped onto externally defined data structures, there is a need, and it is handled with:

struct Foo
{
    align (4):	// use 4 byte alignment
    ...
}

Macros

Preprocessor macros add powerful features and flexibility to C. But they have a downside:

  • Macros have no concept of scope; they are valid from the point of definition to the end of the source. They cut a swath across .h files, nested code, etc. When #include'ing tens of thousands of lines of macro definitions, it becomes problematical to avoid inadvertent macro expansions.
  • Macros are unknown to the debugger. Trying to debug a program with symbolic data is undermined by the debugger only knowing about macro expansions, not the macros themselves.
  • Macros make it impossible to tokenize source code, as an earlier macro change can arbitrarily redo tokens.
  • The purely textual basis of macros leads to arbitrary and inconsistent usage, making code using macros error prone. (Some attempt to resolve this was introduced with templates in C++.)
  • Macros are still used to make up for deficits in the language's expressive capability, such as for "wrappers" around header files.

Here's an enumeration of the common uses for macros, and the corresponding feature in D:

  1. Defining literal constants:

    The C Preprocessor Way

    #define VALUE	5

    The D Way

    const int VALUE = 5;
  2. Creating a list of values or flags:

    The C Preprocessor Way

    int flags:
#define FLAG_X	0x1
#define FLAG_Y	0x2
#define FLAG_Z	0x4
...
flags |= FLAG_X;

    The D Way

    enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
FLAGS flags;
...
flags |= FLAGS.X;
  3. Distinguishing between ascii chars and wchar chars:

    The C Preprocessor Way

    #if UNICODE
    #define dchar	wchar_t
    #define TEXT(s)	L##s
#else
    #define dchar	char
    #define TEXT(s)	s
#endif

...
dchar h[] = TEXT("hello");

    The D Way

    dchar[] h = "hello";
    D's optimizer will inline the function, and will do the conversion of the string constant at compile time.

  4. Supporting legacy compilers:

    The C Preprocessor Way

    #if PROTOTYPES
#define P(p)	p
#else
#define P(p)	()
#endif
int func P((int x, int y));

    The D Way

    By making the D compiler open source, it will largely avoid the problem of syntactical backwards compatibility.
  5. Type aliasing:

    The C Preprocessor Way

    #define INT 	int

    The D Way

    alias int INT;
  6. Using one header file for both declaration and definition:

    The C Preprocessor Way

    #define EXTERN extern
#include "declarations.h"
#undef EXTERN
#define EXTERN
#include "declarations.h"
    In declarations.h:
    EXTERN int foo;

    The D Way

    The declaration and the definition are the same, so there is no need to muck with the storage class to generate both a declaration and a definition from the same source.
  7. Lightweight inline functions:

    The C Preprocessor Way

    #define X(i)	((i) = (i) / 3)

    The D Way

    int X(ref int i) { return i = i / 3; }
    The compiler optimizer will inline it; no efficiency is lost.
  8. Assert function file and line number information:

    The C Preprocessor Way

    #define assert(e)	((e) || _assert(__LINE__, __FILE__))

    The D Way

    assert() is a built-in expression primitive. Giving the compiler such knowledge of assert() also enables the optimizer to know about things like the _assert() function never returns.
  9. Setting function calling conventions:

    The C Preprocessor Way

    #ifndef _CRTAPI1
#define _CRTAPI1 __cdecl
#endif
#ifndef _CRTAPI2
#define _CRTAPI2 __cdecl
#endif

int _CRTAPI2 func();

    The D Way

    Calling conventions can be specified in blocks, so there's no need to change it for every function:
    extern (Windows)
{
    int onefunc();
    int anotherfunc();
}
  10. Hiding __near or __far pointer weirdness:

    The C Preprocessor Way

    #define LPSTR	char FAR *

    The D Way

    D doesn't support 16 bit code, mixed pointer sizes, and different kinds of pointers, and so the problem is just irrelevant.
  11. Simple generic programming:

    The C Preprocessor Way

    Selecting which function to use based on text substitution:
    #ifdef UNICODE
int getValueW(wchar_t *p);
#define getValue getValueW
#else
int getValueA(char *p);
#define getValue getValueA
#endif

    The D Way

    D enables declarations of symbols that are aliases of other symbols:
    version (UNICODE)
{
    int getValueW(wchar[] p);
    alias getValueW getValue;
}
else
{
    int getValueA(char[] p);
    alias getValueA getValue;
}

Conditional Compilation

The C Preprocessor Way

Conditional compilation is a powerful feature of the C preprocessor, but it has its downside:

  • The preprocessor has no concept of scope. #if/#endif can be interleaved with code in a completely unstructured and disorganized fashion, making things difficult to follow.
  • Conditional compilation triggers off of macros - macros that can conflict with identifiers used in the program.
  • #if expressions are evaluated in subtly different ways than C expressions are.
  • The preprocessor language is fundamentally different in concept than C, for example, whitespace and line terminators mean things to the preprocessor that they do not in C.

The D Way

D supports conditional compilation:

  1. Separating version specific functionality into separate modules.
  2. The debug statement for enabling/disabling debug harnesses, extra printing, etc.
  3. The version statement for dealing with multiple versions of the program generated from a single set of sources.
  4. The if (0) statement.
  5. The /+ +/ nesting comment can be used to comment out blocks of code.

Code Factoring

The C Preprocessor Way

It's common in a function to have a repetitive sequence of code to be executed in multiple places. Performance considerations preclude factoring it out into a separate function, so it is implemented as a macro. For example, consider this fragment from a byte code interpreter:

unsigned char *ip;	// byte code instruction pointer
int *stack;
int spi;		// stack pointer
...
#define pop()		(stack[--spi])
#define push(i)		(stack[spi++] = (i))
while (1)
{
    switch (*ip++)
    {
    case ADD:
        op1 = pop();
        op2 = pop();
        result = op1 + op2;
        push(result);
        break;

    case SUB:
    ...
    }
}

This suffers from numerous problems:

  1. The macros must evaluate to expressions and cannot declare any variables. Consider the difficulty of extending them to check for stack overflow/underflow.
  2. The macros exist outside of the semantic symbol table, so remain in scope even outside of the function they are declared in.
  3. Parameters to macros are passed textually, not by value, meaning that the macro implementation needs to be careful to not use the parameter more than once, and must protect it with ().
  4. Macros are invisible to the debugger, which sees only the expanded expressions.

The D Way

D neatly addresses this with nested functions:

ubyte* ip;		// byte code instruction pointer
int[] stack;		// operand stack
int spi;		// stack pointer
...

int pop()        { return stack[--spi]; }
void push(int i) { stack[spi++] = i; }

while (1)
{
    switch (*ip++)
    {
    case ADD:
        op1 = pop();
        op2 = pop();
        push(op1 + op2);
        break;

    case SUB:
    ...
    }
}

The problems addressed are:

  1. The nested functions have available the full expressive power of D functions. The array accesses already are bounds checked (adjustable by compile time switch).
  2. Nested function names are scoped just like any other name.
  3. Parameters are passed by value, so need to worry about side effects in the parameter expressions.
  4. Nested functions are visible to the debugger.

Additionally, nested functions can be inlined by the implementation resulting in the same high performance that the C macro version exhibits.

#error and Static Asserts

Static asserts are user defined checks made at compile time; if the check fails the compile issues an error and fails.

The C Preprocessor Way

The first way is to use the #error preprocessing directive:

#if FOO || BAR
    ... code to compile ...
#else
#error "there must be either FOO or BAR"
#endif

This has the limitations inherent in preprocessor expressions (i.e. integer constant expressions only, no casts, no sizeof, no symbolic constants, etc.).

These problems can be circumvented to some extent by defining a static_assert macro (thanks to M. Wilson):

#define static_assert(_x) do { typedef int ai[(_x) ? 1 : 0]; } while(0)

and using it like:

void foo(T t)
{
    static_assert(sizeof(T) < 4);
    ...
}

This works by causing a compile time semantic error if the condition evaluates to false. The limitations of this technique are a sometimes very confusing error message from the compiler, along with an inability to use a static_assert outside of a function body.

The D Way

D has the static assert, which can be used anywhere a declaration or a statement can be used. For example:

version (FOO)
{
    class Bar
    {
    const int x = 5;
    static assert(Bar.x == 5 || Bar.x == 6);

    void foo(T t)
    {
        static assert(T.sizeof < 4);
        ...
    }
    }
}
else version (BAR)
{
    ...
}
else
{
    static assert(0);	// unsupported version
}

Template Mixins

D template mixins superficially look just like using C's preprocessor to insert blocks of code and parse them in the scope of where they are instantiated. But the advantages of mixins over macros are:

  1. Mixins substitute in parsed declaration trees that pass muster with the language syntax, macros substitute in arbitrary preprocessor tokens that have no organization.
  2. Mixins are in the same language. Macros are a separate and distinct language layered on top of C++, with its own expression rules, its own types, its distinct symbol table, its own scoping rules, etc.
  3. Mixins are selected based on partial specialization rules, macros have no overloading.
  4. Mixins create a scope, macros do not.
  5. Mixins are compatible with syntax parsing tools, macros are not.
  6. Mixin semantic information and symbol tables are passed through to the debugger, macros are lost in translation.
  7. Mixins have override conflict resolution rules, macros just collide.
  8. Mixins automatically create unique identifiers as required using a standard algorithm, macros have to do it manually with kludgy token pasting.
  9. Mixin value arguments with side effects are evaluated once, macro value arguments get evaluated each time they are used in the expansion (leading to weird bugs).
  10. Mixin argument replacements don't need to be ‘protected’ with parentheses to avoid operator precedence regrouping.
  11. Mixins can be typed as normal D code of arbitrary length, multiline macros have to be backslash line-spliced, can't use // to end of line comments, etc.
  12. Mixins can define other mixins. Macros cannot create other macros.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Comparison - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Comparison

To D, or not to D.

William Nerdspeare

This table is a quick and rough list of various features of D that can be used to compare with other languages. While many capabilities are available with standard libraries, this table is for features built in to the core language itself. Rationale.

D Language Feature Comparison Table
Feature | D
Garbage Collection | Yes
Functions
Function delegates | Yes
Function overloading | Yes
Out function parameters | Yes
Nested functions | Yes
Function literals | Yes
Closures | Yes
Typesafe variadic arguments | Yes
Lazy function argument evaluation | Yes
Compile time function evaluation | Yes
Arrays
Lightweight arrays | Yes
Resizeable arrays | Yes
Built-in strings | Yes
Array slicing | Yes
Array bounds checking | Yes
Array literals | Yes
Associative arrays | Yes
Strong typedefs | Yes
String switches | Yes
Aliases | Yes
OOP
Object Oriented | Yes
Multiple Inheritance | No
Interfaces | Yes
Operator overloading | Yes
Modules | Yes
Dynamic class loading | No
Nested classes | Yes
Inner (adaptor) classes | Yes
Covariant return types | Yes
Properties | Yes
Performance
Inline assembler | Yes
Direct access to hardware | Yes
Lightweight objects | Yes
Explicit memory allocation control | Yes
Independent of VM | Yes
Direct native code gen | Yes
Generic Programming
Class Templates | Yes
Function Templates | Yes
Implicit Function Template Instantiation | Yes
Partial and Explicit Specialization | Yes
Value Template Parameters | Yes
Template Template Parameters | Yes
Variadic Template Parameters | Yes
Template Constraints | Yes
Mixins | Yes
static if | Yes
is expressions | Yes
typeof | Yes
foreach | Yes
Implicit Type Inference | Yes
Reliability
Contract Programming | Yes
Unit testing | Yes
Static construction order | Yes
Guaranteed initialization | Yes
RAII (automatic destructors) | Yes
Exception handling | Yes
Scope guards | Yes
try-catch-finally blocks | Yes
Thread synchronization primitives | Yes
Compatibility
C-style syntax | Yes
Enumerated types | Yes
Support all C types | Yes
80 bit floating point | Yes
Complex and Imaginary | Yes
Direct access to C | Yes
Use existing debuggers | Yes
Struct member alignment control | Yes
Generates standard object files | Yes
Macro text preprocessor | No
Other
Conditional compilation | Yes
Unicode source text | Yes
Documentation comments | Yes

Notes

Object Oriented
This means support for classes, member functions, inheritance, and virtual function dispatch.

Inline assembler
Many C and C++ compilers support an inline assembler, but this is not a standard part of the language, and implementations vary widely in syntax and quality.

Interfaces
Support in C++ for interfaces is weak enough that an IDL (Interface Description Language) was invented to compensate.

Modules
Many correctly argue that C++ doesn't really have modules. But C++ namespaces coupled with header files share many features with modules.

Garbage Collection
The Hans-Boehm garbage collector can be successfully used with C and C++, but it is not a standard part of the language.

Implicit Type Inference
This refers to the ability to pick up the type of a declaration from its initializer.

Contract Programming
The Digital Mars C++ compiler supports Contract Programming as an extension. Compare some C++ techniques for doing Contract Programming with D.

Resizeable arrays
Part of the standard library for C++ implements resizeable arrays, however, they are not part of the core language. A conforming freestanding implementation of C++ (C++98 17.4.1.3) does not need to provide these libraries.

Built-in Strings
Part of the standard library for C++ implements strings, however, they are not part of the core language. A conforming freestanding implementation of C++ (C++98 17.4.1.3) does not need to provide these libraries.

Strong typedefs
Strong typedefs can be emulated in C/C++ by wrapping a type in a struct. Getting this to work right requires much tedious programming, and so is considered as not supported.

Use existing debuggers
By this is meant using common debuggers that can operate using debug data in common formats embedded in the executable. A specialized debugger useful only with that language is not required.

Struct member alignment control
Although many C/C++ compilers contain pragmas to specify struct alignment, these are nonstandard and incompatible from compiler to compiler.
The C# standard ECMA-334 25.5.8 says only this about struct member alignment: "The order in which members are packed into a struct is unspecified. For alignment purposes, there may be unnamed padding at the beginning of a struct, within a struct, and at the end of the struct. The contents of the bits used as padding are indeterminate." Therefore, although Microsoft may have extensions to support specific member alignment, they are not an official part of standard C#.

Support all C types
C99 adds many new types not supported by C++.

80 bit floating point
While the standards for C and C++ specify long doubles, few compilers (besides Digital Mars C/C++) actually implement 80 bit (or longer) floating point types.

Mixins
Mixins have many different meanings in different programming languages. D mixins mean taking an arbitrary sequence of declarations and inserting (mixing) them into the current scope. Mixins can be done at the global, class, struct, or local level.

C++ Mixins
C++ mixins refer to a couple different techniques. The first is analogous to D's interface classes. The second is to create a template of the form:
template <class Base> class Mixin : public Base
{
    ... mixin body ...
}
D mixins are different.

Static If
The C and C++ preprocessor directive #if would appear to be equivalent to the D static if. But there are major and crucial differences - the #if does not have access to any of the constants, types, or symbols of the program. It can only access preprocessor macros. See this example.

Is Expressions
Is expressions enable conditional compilation based on the characteristics of a type. This is done after a fashion in C++ using template parameter pattern matching. See this example for a comparison of the different approaches.

Inner (adaptor) classes
A nested class is one whose definition is within the scope of another class. An inner class is a nested class that can also reference the members and fields of the lexically enclosing class; one can think of it as if it contained a 'this' pointer to the enclosing class.

Documentation comments
Documentation comments refer to a standardized way to produce documentation from the source code file using specialized comments.

Errors

If I've made any errors in this table, please contact me so I can correct them.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


D 2.0 Specific Features - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

D 2.0 Specific Features

D 2.0 has many substantial language and library enhancements compared with D 1.0. This list does not include bug fixes or changes that were also made to D 1.0. See the D1 to D2 Migration Guide for help in converting source code.

Core Language Changes

  • opAssign can no longer be overloaded for class objects.
  • Added pure keyword.
  • Extended enums to allow declaration of manifest constants.
  • Added const/immutable structs, classes and interfaces.
  • Added const and immutable to IsExpressions.
  • Added typeof(return) type specifier.
  • Added overloadable unary * operation as opStar().
  • Full closure support added.
  • Transformed all of string, wstring, and dstring into immutable definitions
    • .
  • Added Overload Sets for functions and templates.
  • std.math.sin, cos, tan are now evaluated at compile time if the argument is a constant.
  • Added C++ interface for ‘plugins’.
  • Changed result type of IsExpression from int to bool.
  • Added optional TemplateParameterList to IsExpression.
  • Added warning when override is omitted.
  • Added new syntax for string literals (delimited, heredoc, D tokens)
  • Added __EOF__ token
  • Added D_Version2 predefined identifier to indicate this is a D version 2.0 compiler
  • Added .idup property for arrays to create immutable copies.
  • Added transitive const and immutable.
  • in parameter storage class now means scope const.
  • class and struct invariant declarations now must have a ().
  • Added isSame and compiles to __traits.
  • Added ForeachRangeStatement
    • .

Phobos Library Changes

  • std.algorithm: new module
  • std.bitarray: scheduled for deprecation
  • std.bitmanip: new module with the content of std.bitarray plus the bitfields, FloatRep, and DoubleRep templates
  • std.contracts: new module
  • std.conv: Added parse and assumeUnique. Made conv_error a template parameterized on the types being converted. Massive additions.
  • std.file: added dirEntries.
  • std.format: Added raw ('r') format specifier for writef*.
  • std.functional: new module
  • std.getopt: new module.
  • std.hiddenfunc: new module
  • std.math: Made nextafter visible for all floating types. Added approxEqual template.
  • std.numeric: new module
  • std.path: Added rel2abs (Linux version only). Added the basename and dirname functions (which alias the less gainful names getBaseName and getDirectoryName)
  • std.process: Made getpid visible in Linux builds
  • std.stdio: Added writeln() and write(), writef() can now only accept a format as its first argument. Added optional terminator to readln. Added functions fopen, popen, lines and chunks.
  • std.string: Added munch function and added function chompPrefix.
  • std.random: Major addition of engines and distributions.
  • std.traits: new module
  • std.typecons: new module
  • std.variant: new module.
  • Incorporated many of the Tango GC structural differences (much more to go still).
  • Overhaul phobos linux.mak and add documentation build logic
  • Moved next member from Object.Error to Object.Exception
  • Renamed linux library from libphobos.a to libphobos2.a
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Downloads - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Downloads

DMD - Digital Mars D Programming Language version 2
Download | Version | CPU | Operating System | Product
Download dmd.2.060.zip | 2.060 | i386, x86_64 |  | dmd D 2.0 compiler, all platforms
Download dmd Windows installer | 2.060 | i386 | Win32 | dmd D 2.0 compiler 1-click install for Windows
Download dmd 2.060 OSX installer (dmg) | 2.060 | x86_64 | OSX Lion | dmd D 2.0 compiler .dmg installer for OSX
Download dmd_2.060-0_i386.deb | 2.060 | i386 |  | dmd D 2.0 compiler 1-click install for Ubuntu/Debian
Download dmd_2.060-0_amd64.deb | 2.060 | x86_64 |  | dmd D 2.0 compiler 1-click install for Ubuntu/Debian
Download dmd-2.060-0.fedora.i386.rpm | 2.060 | i386 | Fedora | dmd D 2.0 compiler 1-click install as rpm
Download dmd-2.060-0.fedora.x86_64.rpm | 2.060 | x86_64 | Fedora | dmd D 2.0 compiler 1-click install as rpm
Download dmd-2.060-0.openSUSE.i386.rpm | 2.060 | i386 | OpenSUSE | dmd D 2.0 compiler 1-click install as rpm
Download dmd-2.060-0.openSUSE.x86_64.rpm | 2.060 | x86_64 | OpenSUSE | dmd D 2.0 compiler 1-click install as rpm
2.0 changelog | all |  |  | other dmd 2.0 versions

DMD - Digital Mars D Programming Language version 1 (please note: D1 will be discontinued effective December 31, 2012)
Download | Version | CPU | Operating System(s) | Product
Download dmd.1.075.zip | 1.075 | -- |  | dmd D 1.0 compiler, all platforms
Download dmd Windows installer | 1.075 | i386 | Win32 | dmd D 1.0 compiler 1-click install for Windows
Download dmd OSX installer (dmg) | 1.075 | x86_64 | OSX Lion | dmd D 1.0 compiler .dmg installer for OSX
Download dmd_1.075-0_i386.deb | 1.075 | i386 |  | dmd D 1.0 compiler 1-click install for Ubuntu/Debian
Download dmd_1.075-0_amd64.deb | 1.075 | x86_64 |  | dmd D 1.0 compiler 1-click install for Ubuntu/Debian
Download dmd-1.075-0.fedora.i386.rpm | 1.075 | i386 | Fedora | dmd D 1.0 compiler 1-click install as rpm
Download dmd-1.075-0.fedora.x86_64.rpm | 1.075 | x86_64 | Fedora | dmd D 1.0 compiler 1-click install as rpm
Download dmd-1.075-0.openSUSE.i386.rpm | 1.075 | i386 | OpenSUSE | dmd D 1.0 compiler 1-click install as rpm
Download dmd-1.075-0.openSUSE.x86_64.rpm | 1.075 | x86_64 | OpenSUSE | dmd D 1.0 compiler 1-click install as rpm
Download dmd.1.030.zip | 1.030 | i386 |  | dmd D 1.0 compiler
1.0 changelog | all |  |  | other dmd 1.0 versions

DMC - Digital Mars C and C++ Compiler
Download | Version | CPU | Operating System(s) | Product
Download dmc.zip | 8.50 | i386 | Win32 | C++ Compiler and Utilities

GDC - D Programming Language for GCC
Download | Version | CPU | Operating System(s) | Product
GDC | 2.058 | i386, x86_64 | Win32 | GNU D Compiler
GDC | HEAD | i386, x86_64, armel, armhf, mips, mipsel, powerpc, ia64, s390, sparc |  | GNU D Compiler

LDC - D Programming Language for LLVM
Download | Version | CPU | Operating System(s) | Product
ldc2-0.10.0-linux-x86_64.tar.gz | 0.10.0 (2.060) | x86_64 | Linux | LDC 64-bit Linux binaries
ldc2-0.10.0-linux-x86.tar.gz | 0.10.0 (2.060) | i386 | Linux | LDC 32-bit Linux binaries
ldc2-0.10.0-osx-x86_64.tar.gz | 0.10.0 (2.060) | x86_64 | OSX Lion | LDC Mac OS X 10.7+ binaries
ldc-0.10.0-src.tar.gz | 0.10.0 (2.060) | i386, x86_64 |  | LDC source

Documentation Downloads

  • Download D Programming Language Specification 2.0 ebook
  • Download DMD 1.0 pdf English

Other Downloads

  • C and C++ compiler downloads
  • Download DMDScript source
  • Download Empire 2.01 source
  • Download DMD2 compatible cURL 7.24.0
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


DMD Compiler for Linux - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

DMD Compiler for Linux

  • dmd for Windows
  • dmd for OSX
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 and 64 bit x86-64 Linux operating system
  3. Gnu C compiler (gcc)

Files

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/linux/bin/dmd
D compiler executable
dmd2/linux/bin/dumpobj
Elf file dumper
dmd2/linux/bin/obj2asm
Elf file disassembler
dmd2/linux/bin/shell
Simple command line shell
dmd2/linux/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/linux/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.a)

Installation

  • Unzip the archive into your home directory. It will create a ~/dmd directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Copy dmd.conf to /etc:
    cp dmd2/linux/bin/dmd.conf /etc
  • Put dmd2/linux/bin on your PATH, or copy the linux executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp dmd2/linux/lib/libphobos2.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile. The file may contain single-line comments starting with the hash symbol (#).
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory. -op can be used if the original package hierarchy should be retained
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries).
    -g
    add Dwarf symbolic debug info with D extensions for debuggers such as ZeroBUGS
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory. -op can be used if the original package hierarchy should be retained
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -map
    generate a .map file
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory. -op can be used if the original package hierarchy should be retained
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object, interface, or Ddoc file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -property
    enforce use of @property on property functions
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts and asserts. Array bounds checking is not done for system and trusted functions.
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]

DFLAGS=-I%@P%/../src/phobos -I%@P%/../src/druntime/import

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~/dmd2/src/dmd
make -f linux.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/linux/bin/dmd
cd ../phobos
make -f linux.mak DMD=~/dmd2/linux/bin/dmd
    Forums | Comments | Search | Downloads | Home
    Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


DMD Compiler for Windows - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

DMD Compiler for Windows

  • dmd for Linux
  • dmd for OSX
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Example
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • sc.ini Initialization File
  • Common Installation Problems
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit Windows (Win32) operating system, such as Windows XP
  3. Download dmc.zip (C and C++ compiler) for Win32 (not required, but it complements dmd for Windows)

Files

\dmd2\src\phobos\
D runtime library source
\dmd2\src\dmd\
D compiler front end source under dual (GPL and Artistic) license
\dmd2\html\d\
Documentation
\dmd2\samples\d\
Sample D programs
\dmd2\windows\bin\dmd.exe
D compiler executable
\dmd2\windows\bin\shell.exe
Simple command line shell
\dmd2\windows\bin\sc.ini
Global compiler settings
\dmd2\windows\lib\phobos.lib
D runtime library

Installation

Open a console window (for Windows XP this is done by clicking on [Start][Command Prompt]). All the tools are command line tools, which means they are run from a console window. Switch to the root directory. Unzip the files in the root directory. dmd.zip will create a \dmd2 directory with all the files in it. dmc.zip will create a \dm directory with all the files in it.

A typical session might look like:

C:\Documents and Settings\Your Name>cd \
C:\>unzip dmd.zip
C:\>unzip dmc.zip

Example

Run:

\dmd2\windows\bin\shell all.sh

in the \dmd2\samples\d directory for several small examples.

Compiler Arguments and Switches

dmd files... -switches...
files...
File Extensions
Extension | File Type
none | D source files
.d | D source files
.dd | Ddoc source files
.di | D interface files
.obj | Object files to link in
.lib | Object code libraries to search
.exe | Output executable file
.def | module definition file
.res | resource file
@cmdfile
If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile. The file may contain single-line comments starting with the hash symbol (#).
-c
compile only, do not link
-cov
instrument for code coverage analysis
-D
generate documentation from source
-Dd docdir
write documentation file to docdir directory. -op can be used if the original package hierarchy should be retained
-Df filename
write documentation file to filename
-d
allow deprecated features
-debug
compile in debug code
-debug=level
compile in debug level <= level
-debug=ident
compile in debug identifier ident
-debuglib=libname
link in libname as the default library when compiling for symbolic debugging instead of phobos.lib
-defaultlib=libname
link in libname as the default library when not compiling for symbolic debugging instead of phobos.lib
-deps=filename
write module dependencies as text to filename
-g
add CodeView 4 symbolic debug info with D extensions for debuggers such as Ddbg
-gc
add CodeView 4 symbolic debug info in C format for debuggers such as \dmd2\bin\windbg
-gs
always generate standard stack frame
-H
generate D interface file
-Hd dir
write D interface file to dir directory. -op can be used if the original package hierarchy should be retained
-Hf filename
write D interface file to filename
--help
print brief help to console
-I path
where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
-ignore
ignore unsupported pragmas
-inline
inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
-J path
where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
-L linkerflag
pass linkerflag to the linker , for example, -L/ma/li
-lib
generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
-man
open default browser on this page
-map
generate a .map file
-noboundscheck
turns off all array bounds checking, even for safe functions
-O
Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
-o-
Suppress generation of object file. Useful in conjuction with -D or -H flags.
-od objdir
write object files relative to directory objdir instead of to the current directory. -op can be used if the original package hierarchy should be retained
-of filename
Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
-op
normally the path for .d source files is stripped off when generating an object, interface, or Ddoc file name. -op will leave it on.
-profile
profile the runtime performance of the generated code
-property
enforce use of @property on property functions
-quiet
suppress non-essential compiler messages
-release
compile release version, which means not generating code for contracts and asserts. Array bounds checking is not done for system and trusted functions.
-run srcfile args... compile
link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .obj or executable file is left behind.
-unittest
compile in unittest code, turns on asserts, and sets the unittest version identifier
-v
verbose
-version=level
compile in version level >= level
-version=ident
compile in version identifier ident
-vtls
print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
-w
enable warnings
-wi
enable informational warnings (i.e. compilation still proceeds normally)
-X
generate JSON file
-Xf filename
write JSON file to filename

Empty switches, i.e. "", are ignored.

Linking

Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

The programs must be linked with the D runtime library phobos.lib, followed by the C runtime library snn.lib. This is done automatically as long as the directories for the libraries are on the LIB environment variable path. A typical way to set LIB would be:

set LIB=\dmd2\lib;\dm\lib

If the dmd command is used to both compile and link to an executable, it will make certain optimizations that are valid only for Windows executable files. Do not use the resulting .obj files in a DLL. To compile modules into .obj files that can be used in an exe or DLL, compile with -c.

Linking is done using the optlink linker.

Environment Variables

The D compiler dmd uses the following environment variables:

DFLAGS
The value of DFLAGS is treated as if it were appended to the command line to dmd.exe.
LIB
The linker uses LIB to search for library files. For D, it will normally be set to:
set LIB=\dmd2\lib;\dm\lib
LINKCMD
dmd normally runs the linker by looking for link.exe along the PATH. To use a specific linker instead, set the LINKCMD environment variable to it. For example:
set LINKCMD=\dmd\windows\bin\link
PATH
If the linker is not found in the same directory as dmd.exe is in, the PATH is searched for it. Note: other linkers named link.exe will likely not work. Make sure the Digital Mars link.exe is found first in the PATH before other link.exe's, or use LINKCMD to specifically identify which linker to use.

sc.ini Initialization File

dmd will look for the initialization file sc.ini in the following sequence of directories:

  1. current working directory
  2. directory specified by the HOME environment variable
  3. directory dmd.exe resides in

If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

Initialization File Format

Comments are lines that begin with ; and are ignored.

Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

; sc.ini file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]
LIB="%@P%\..\lib";\dm\lib

DFLAGS="-I%@P%\..\src\phobos" "-I%@P%\..\src\druntime\import"
LINKCMD="%@P%\..\..\dm\bin"
DDOCFILE=mysettings.ddoc

Location Independence of sc.ini

The %@P% is replaced with the path to sc.ini. Thus, if the fully qualified file name sc.ini is c:\dmd2\bin\sc.ini, then %@P% will be replaced with c:\dmd2\bin, and the above sc.ini will be interpreted as:

[Environment]
LIB="c:\dmd2\bin\..\lib";\dm\lib

DFLAGS="-Ic:\dmd2\bin\..\src\phobos" "-Ic:\dmd2\bin\..\src\druntime\import"
LINKCMD="c:\dmd2\bin\..\..\dm\bin"
DDOCFILE=mysettings.ddoc

This enables your dmd setup to be moved around without having to re-edit sc.ini.

Common Installation Problems

  • Using Cygwin's unzip utility has been known to cause strange problems.
  • Running the compiler under Cygwin's command shell has been also known to cause problems. Try getting it to work under the regular Windows shell cmd.exe before trying Cygwin's.
  • Installing dmd and dmc into directory paths with spaces in them causes problems.

Differences between Windows and Linux versions

  • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

D Interface Files

When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

The advantages of using a D interface file for imports rather than a D source file are:

  • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
  • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

Building Executables

dmd can build an executable much faster if as many of the source files as possible are put on the command line.

Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

Building Libraries

There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.obj and existing library def.lib which are all to be combined into a library foo.lib:

  1. Compile modules separately and then run the librarian on them:
    dmd -c foo.d
dmd -c bar.d
lib -c -p32 foo.lib foo.obj bar.obj abc.obj def.lib
del foo.obj bar.obj
    This option is typical when using a makefile to avoid compiling modules that have already been compiled.
  2. Compile modules together and then run the librarian on them:
    dmd -c foo.d bar.d
lib -c -p32 foo.lib foo.obj bar.obj abc.obj def.lib
del foo.obj bar.obj
  3. Use dmd to compile and build library in one operation:
    dmd -lib foo.d bar.d abc.obj def.lib
    No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

Compiling dmd

Complete source code is provided to build the compiler. Follow these steps:

cd \dmd2\src\dmd
make -f win32.mak

Compiling Phobos

Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

cd \dmd2\src\druntime
make -f win32.mak DMD=\dmd2\windows\bin\dmd
cd ..\phobos
make -f win32.mak DMD=\dmd2\windows\bin\dmd
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


DMD Compiler for OSX - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

DMD Compiler for OSX

  • dmd for Windows
  • dmd for Linux
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 Mac OSX operating system
  3. Gnu C compiler (gcc)

Files

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/osx/bin/dmd
D compiler executable
dmd2/osx/bin/dumpobj
Mach-O file dumper
dmd2/osx/bin/obj2asm
Mach-O file disassembler
dmd2/osx/bin/shell
Simple command line shell
dmd2/osx/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/osx/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.a)

Installation

  • Put the dmd zip file into your home directory, and unzip it:
    unzip dmd.VERSION.zip
    where VERSION is the particular version of the zip file.
  • It will create a ~/dmd2 directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Verify that this works by creating hello.d in your home directory with these contents:
    import std.stdio;

void main() {
    writeln("hello world!");
}
    and compile and run it with:
    dmd2/osx/bin/dmd hello
./hello
    and it should print:
    hello world!
  • To install a global copy:
  • Copy binaries to /usr/local/bin:
    sudo cp dmd2/osx/bin/{dmd,dumpobj,obj2asm,shell,rdmd} /usr/local/bin
sudo cp dmd2/osx/bin/dmdx.conf /usr/local/bin/dmd.conf
  • Copy the library to /usr/lib:
    sudo cp dmd2/osx/lib/libphobos2.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile. The file may contain single-line comments starting with the hash symbol (#).
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory. -op can be used if the original package hierarchy should be retained
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries). This is always on for OSX.
    -g
    add Dwarf symbolic debug info with D extensions for debuggers
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory. -op can be used if the original package hierarchy should be retained
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, Safari is assumed.
    -map
    generate a .map file
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory. -op can be used if the original package hierarchy should be retained
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object, interface, or Ddoc file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -property
    enforce use of @property on property functions
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts and asserts. Array bounds checking is not done for system and trusted functions.
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]

DFLAGS=-I%@P%/../src/phobos -I%@P%/../src/druntime/import

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~/dmd2/src/dmd
make -f osx.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/osx/bin/dmd
cd ../phobos
make -f osx.mak DMD=~/dmd2/osx/bin/dmd
    Forums | Comments | Search | Downloads | Home
    Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


DMD Compiler for FreeBSD - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

DMD Compiler for FreeBSD

  • dmd for Windows
  • dmd for Linux
  • dmd for OSX
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 FreeBSD 7.1 operating system
  3. Gnu C compiler (gcc)

Files

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/freebsd/bin/dmd
D compiler executable
dmd2/freebsd/bin/dumpobj
Elf file dumper
dmd2/freebsd/bin/obj2asm
Elf file disassembler
dmd2/freebsd/bin/shell
Simple command line shell
dmd2/freebsd/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/freebsd/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.a)

Installation

  • Unzip the archive into your home directory. It will create a ~/dmd directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Copy dmd.conf to /etc:
    cp dmd2/freebsd/bin/dmd.conf /etc
  • Put dmd2/freebsd/bin on your PATH, or copy the FreeBSD executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp dmd2/freebsd/lib/libphobos2.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile. The file may contain single-line comments starting with the hash symbol (#).
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory. -op can be used if the original package hierarchy should be retained
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries).
    -g
    add Dwarf symbolic debug info with D extensions for debuggers
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory. -op can be used if the original package hierarchy should be retained
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -map
    generate a .map file
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory. -op can be used if the original package hierarchy should be retained
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object, interface, or Ddoc file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -property
    enforce use of @property on property functions
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts and asserts. Array bounds checking is not done for system and trusted functions.
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]

DFLAGS=-I%@P%/../src/phobos -I%@P%/../src/druntime/import

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~/dmd2/src/dmd
make -f freebsd.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/freebsd/bin/dmd
cd ../phobos
make -f freebsd.mak DMD=~/dmd2/freebsd/bin/dmd
    Forums | Comments | Search | Downloads | Home
    Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Code Coverage Analysis - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Code Coverage Analysis

A major part of the engineering of a professional software project is creating a test suite for it. Without some sort of test suite, it is impossible to know if the software works at all. The D language has many features to aid in the creation of test suites, such as unit tests and contract programming. But there's the issue of how thoroughly the test suite tests the code. The profiler can give valuable information on which functions were called, and by whom. But to look inside a function, and determine which statements were executed and which were not, requires a code coverage analyzer.

A code coverage analyzer will help in these ways:

  1. Expose code that is not exercised by the test suite. Add test cases that will exercise it.
  2. Identify code that is unreachable. Unreachable code is often the leftover result of program design changes. Unreachable code should be removed, as it can be very confusing to the maintenance programmer.
  3. It can be used to track down why a particular section of code exists, as the test case that causes it to execute will illuminate why.
  4. Since execution counts are given for each line, it is possible to use the coverage analysis to reorder the basic blocks in a function to minimize jmps in the most used path, thus optimizing it.

Experience with code coverage analyzers show that they dramatically reduce the number of bugs in shipping code. But it isn't a panacea, a code coverage analyzer won't help with:

  1. Identifying race conditions.
  2. Memory consumption problems.
  3. Pointer bugs.
  4. Verifying that the program got the correct result.

Code coverage analysers are available for many popular languages such as C++, but they are often third party products that integrate poorly with the compiler, and are often very expensive. A big problem with third party products is, in order to instrument the source code, they must include what is essentially a full blown compiler front end for the same language. Not only is this an expensive proposition, it often winds up out of step with the various compiler vendors as their implementations change and as they evolve various extensions. (gcov, the Gnu coverage analyzer, is an exception as it is both free and is integrated into gcc.)

The D code coverage analyser is built in as part of the D compiler. Therefore, it is always in perfect synchronization with the language implementation. It's implemented by establishing a counter for each line in each module compiled with the -cov switch. Code is inserted at the beginning of each statement to increment the corresponding counter. When the program finishes, the runtime collects all the counters, merges it with the source files, and writes the reports out to listing (.lst) files.

For example, consider the Sieve program:

/* Eratosthenes Sieve prime number calculation. */

import std.stdio;

bit flags[8191];

int main()
{   int     i, prime, k, count, iter;

    writefln("10 iterations");
    for (iter = 1; iter <= 10; iter++)
    {	count = 0;
    flags[] = true;
    for (i = 0; i < flags.length; i++)
    {   if (flags[i])
        {	prime = i + i + 3;
        k = i + prime;
        while (k < flags.length)
        {
            flags[k] = false;
            k += prime;
        }
        count += 1;
        }
    }
    }
    writefln("%d primes", count);
    return 0;
}

Compile and run it with:

dmd sieve -cov
sieve

The output file will be created called sieve.lst, the contents of which are:

      |/* Eratosthenes Sieve prime number calculation. */
       |
       |import std.stdio;
       |
       |bit flags[8191];
       |
       |int main()
      5|{   int     i, prime, k, count, iter;
       |
      1|    writefln("10 iterations");
     22|    for (iter = 1; iter <= 10; iter++)
     10|    {   count = 0;
     10|        flags[] = true;
 163840|        for (i = 0; i < flags.length; i++)
  81910|        {   if (flags[i])
  18990|            {   prime = i + i + 3;
  18990|                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;
       |}
sieve.d is 100% covered

The numbers to the left of the | are the execution counts for that line. Lines that have no executable code are left blank. Lines that have executable code, but were not executed, have a "0000000" as the execution count. At the end of the .lst file, the percent coverage is given.

There are 3 lines with an exection count of 1, these were each executed once. The declaration line for i, prime, etc., has 5 because there are 5 declarations, and the initialization of each declaration counts as one statement.

The first for loop shows 22. This is the sum of the 3 parts of the for header. If the for header is broken up into 3 lines, the data is similarly divided:

     1|    for (iter = 1;
     11|         iter <= 10;
     10|         iter++)

which adds up to 22.

e1&&e2 and e1||e2 expressions conditionally execute the rvalue e2. Therefore, the rvalue is treated as a separate statement with its own counter:

       |void foo(int a, int b)
        |{
       5|   bar(a);
       8|   if (a && b)
       1|	bar(b);
        |}

By putting the rvalue on a separate line, this illuminates things:

       |void foo(int a, int b)
        |{
       5|   bar(a);
       5|   if (a &&
       3|	b)
       1|	bar(b);
        |}

Similarly, for the e?e1:e2 expressions, e1 and e2 are treated as separate statements.

Controlling the Coverage Analyser

When the -cov switch is thrown, the version identifier D_Coverage is defined.

References

Wikipedia
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


rdmd - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

rdmd

Synopsis

In a command prompt:
% cat myprog.d
import std.stdio;
void main()
{
    writeln("Hello, world without explicit compilations!");
}
% rdmd myprog
Hello, world without explicit compilations!
% _
Inside a D program:
% cat myprog.d
#!/usr/bin/env rdmd
import std.stdio;
void main()
{
    writeln("Hello, world with automated script running!");
}
% ./myprog.d
Hello, world with automated script running!
% _
(Under Windows replace cat with type and #!/usr/bin/env rdmd with #!rdmd, the latter assuming that rdmd can be found in your path.)

Description

rdmd is a companion to the dmd compiler that simplifies the typical edit-compile-link-run or edit-make-run cycle to a rapid edit-run cycle. Like make and other tools, rdmd uses the relative dates of the files involved to minimize the amount of work necessary. Unlike make, rdmd tracks dependencies and freshness without requiring additional information from the user.

rdmd:

  • shields its user from the notion that producing a running program from D programming language files may entail several concerted steps against different source files producing various intermediate files;
  • automatically infers and builds dependent files, transitively, by following import directives;
  • recognizes and passes down all of dmd's command-line options;
  • understands how various dmd compiler options (e.g. -release vs. -debug) affect generation of intermediate files, and avoids conflations (e.g., does not unwittingly run a debug executable when the release executable is asked for);
  • recompiles files only on a needed basis, e.g. two invocations of rdmd in sequence without an intervening change to any relevant source file does not produce the executable again.

Usage

rdmd [dmd and rdmd options] progfile[.d] [program arguments]

In addition to dmd's options, rdmd recognizes the following:

--build-only
just build the executable, don't run it
--chatty
write dmd commands to stdout before executing them
--compiler=/path/to/compiler
use the specified compiler (e.g. gdmd) instead of dmd
--dry-run
do not compile, just show what commands would be run (implies --chatty)
--eval=code
evaluate code including it in void main(char[][] args) { ... } (multiple --eval allowed, will be evaluated in turn)
--exclude=package
exclude a package from the build (multiple --exclude allowed)
--force
force a rebuild even if apparently not necessary
--help
show a help message and exit
--loop=code
like --eval, but code will be additionally included in a loop foreach (line; stdin.byLine()) { ... }
--main
add an empty void main() {} function (useful for running unittests)
--makedepend
print dependencies in makefile format and exit
--man
open web browser on manual page
--shebang
rdmd is in a shebang line (put as first argument)

Download

  • View syntax-colored source code
  • Download

Author

Andrei Alexandrescu
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


windbg Debugger - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

windbg Debugger

The Microsoft Windows debugger \dmd2\windows\bin\windbg.exe can be used to symbolically debug D programs, even though it is a C++ debugger. Versions of windbg.exe other than the one supplied may not work with D. (Jascha Wetzel's Ddbg for Windows is also available.)

To prepare a program for symbolic debugging, compile with the -gc switch:

dmd myprogram -gc

To invoke the debugger on it:

windbg myprogram args...

where args... are the command line arguments to myprogram.exe.

When the debugger comes up, entering the command in the command window:

g _Dmain

will execute the program up until the entry into main(). From thence, pressing the F10 key will single step each line of code.

Basic Commands:

F5
Go until breakpoint, an exception is thrown, or the end of the program.
F7
Continue until cursor.
F8
Single step, stepping into function calls.
F10
Single step, stepping over function calls.

For more comprehensive information on windbg, consult the file \dmd2\windows\bin\windbg.hlp.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


htod - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

htod

While D is binary compatible with C code, it cannot compile C code nor C header files. In order for D to link with C code, the C declarations residing in C header files need to be converted to a D module. htod is a migration tool to aid in convering C header files.

htod is built from the front end of the Digital Mars C and C++ compiler. It works just like a C or C++ compiler except that its output is a D module rather than object code.

The macro __HTOD__ is predefined and set to 1, which is handy for improving C header files to give better D output.

Download

htod

Usage

htod cheader.h [dimport.d] [-cpp] [-hc] [-hi] [-hs] [-ht] { C compiler switches }

where:

cheader.h
C or C++ header input file
dimport.d
D source code output file (defaults to cheader.d)
-cpp
Indicates a C++ header file
-hc
By default, htod will insert the C and C++ declarations in a file into the output file prefixed by //C . -hc will suppress this. Use only if you're confident that htod is generating the correct output file (such as if the header file was modified with __HTOD__).
-hi
By default, htod will represent a #include "file" with a corresponding import statement. The -hi will cause the declarations in the included file to be converted to D declarations as well. The declarations in all included files are parsed regardless. -hi is handy when replacing an entire hierarchy of include files with a single D import. System includes like #include <file> are not affected by -hi. See also -hs.
-ht
By default, htod will write types using typedef names as using those names. -ht will cause the underlying types to be used instead. This is very useful for "drilling down" layers of macros, typedefs, and #includes to find out the underlying type.
-hs
Works just like -hi, except that system includes are migrated as well.
C compiler switches
C or C++ compiler switches, such as -D and -I as documented for dmc.

Example

The C test.h file:

unsigned u;
#define MYINT int
void bar(int x, long y, long long z);

Translated with:

htod test.h

Produces the file test.d:

/* Converted to D from test.h by htod */
module test;
//C     unsigned u;
extern (C):
uint u;
//C     #define MYINT int
//C     void bar(int x, long y, long long z);
alias int MYINT;
void  bar(int x, int y, long z);

The C declarations are prefixed by the string "//C ".

Type Mappings

C types are mapped as follows. These mappings are correct for Digital Mars C/C++, but may not be correct for your C compiler. D basic types have fixed sizes, while C basic type sizes are implementation defined.

Mapping C to D types
C type | D type
void | void
_Bool | bool
wchar_t | wchar
char | char
signed char | byte
unsigned char | ubyte
short | short
unsigned short | ushort
int | int
unsigned | uint
long | int
unsigned long | uint
long long | long
unsigned long long | ulong
float | float
double | double
long double | real
_Imaginary float | ifloat
_Imaginary double | idouble
_Imaginary long double | ireal
_Complex float | cfloat
_Complex double | cdouble
_Complex long double | creal

Limitations

There is no one to one correspondence of C declarations to D declarations. A review of the D module output will be necessary to ensure the right decisions are made. Furthermore:

  1. Whereever practical, C headers should be written using typedef's and enum's rather than macros. htod will attempt to convert simple macro #define's to alias and const declarations. Even so, macros are fully expanded before further analysis.
  2. No attempt is made to convert C conditional compilation into D version or static if declarations.
  3. No output is generated for false conditional compilation sections.
  4. htod converts declarations only, it does not convert C code.
  5. Declarations with C++ linkage cannot be converted. A C interface must be made for any C++ code.
  6. C language extensions present in the C .h file may not be recognized.
  7. Pragmas are not translated.
  8. The tag names are assumed to not collide with names in the regular name space.
  9. Any character data that is not ASCII will need to be converted as necessary to UTF.
  10. The C char type is assumed to map to the D char type. However, these should be examined individually to see if they should instead be translated to byte or ubyte types. Whether the C char type is signed or unsigned is implementation defined. The D char type is unsigned.
  11. Named C enum members are not inserted into the surrounding scope as they are in C.
  12. D modules are each in their own name space, but C header files are all in the same global name space. This means that D references to names defined in other modules may need to be qualified.

Bugs

  1. Anything other than the default struct member alignment is not accounted for.
  2. No Linux version.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Change Log - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Change Log

Version D 2.061 Jan 1, 2013
  • New/Changed Features
  • DMD Bugs Fixed
  • Druntime Bugs Fixed
  • Phobos Bugs Fixed
  • Version D 2.061
  • Version D 2.060
  • Version D 2.059
  • Version D 2.058
  • Version D 2.057
  • Version D 2.056
  • Version D 2.055
  • Version D 2.054
  • Version D 2.053
  • Version D 2.052
  • Version D 2.051
  • Version D 2.050
  • Version D 2.049
  • Version D 2.048
  • Version D 2.047
  • Version D 2.046
  • Version D 2.045
  • Version D 2.044
  • Version D 2.043
  • Version D 2.042
  • Version D 2.041
  • Version D 2.040
  • Version D 2.039
  • Version D 2.038
  • Version D 2.037
  • Version D 2.036
  • Version D 2.035
  • Version D 2.034
  • Version D 2.033
  • Version D 2.032
  • Version D 2.031
  • Version D 2.030
  • Version D 2.029
  • Version D 2.028
  • Version D 2.027
  • Version D 2.026
  • Version D 2.025
  • Version D 2.023
  • Version D 2.022
  • Version D 2.021
  • Version D 2.020
  • Version D 2.019
  • Version D 2.018
  • Version D 2.017
  • Version D 2.016
  • Version D 2.015
  • Version D 2.014
  • Version D 2.013
  • Version D 2.012
  • Version D 2.011
  • Version D 2.010
  • Version D 2.009
  • Version D 2.008
  • Version D 2.007
  • Version D 2.006
  • Version D 2.005
  • Version D 2.004
  • Version D 2.003
  • Version D 2.002
  • Version D 2.001
  • Version D 2.000
  • changelog for 1.0
  • tech support
Version D 2.060 Aug 2, 2012

New/Changed Features

  • std.string: The current implementations of std.string.format and string.sformat are scheduled to be replaced in November 2012 with improved implementations which conform to writef. In some, rare cases, this will break code. Please see the documentation for std.string.format and std.string.sformat for details.
  • std.bitmanip: Added peek, read, write, and append for converting ranges of bytes to and from integral types.
  • std.container: Added DList, which is an implementation of a doubly-linked list.
  • Added std.file.tempDir which returns the path to a directory where a program can put temporary files.
  • std.process: Added escapeShellCommand, escapeShellFileName, and escapeWindowsArgument. Documented browse function.
  • std.range: Added RefRange, which effectively makes it possible to pass a range by reference.
  • std.traits: Added KeyType, ValueType, isScalarType, isBasicType, and SetFunctionAttributes templates.
  • std.utf: Added overload of codeLength which operates on a string.
  • std.traits: areAllSafe has been scheduled for deprecation. Please use allSatisfy(isSafe, ...) instead.
  • clear has been renamed to destroy, and clear (as an alias to destroy) has been scheduled for deprpecation.
  • Capitalized std.traits.pointerTarget to PointerTarget. Old one is scheduled for deprecation.
  • std.algorithm.indexOf - which was scheduled for deprecation - has been deprecated (it was easily confused with std.string.indexOf). Please use countUntil instead.
  • std.cpuid - which was scheduled for deprecation - has been deprecated. Please use core.cpuid instead.
  • std.conv.ConvError and ConvOverflowException - which were scheduled for deprecation - have been deprecated. Please catch ConvException and ConvOverflowException instead.
  • The overloads of std.conv.to which were scheduled for deprecation because formattedWrite replaced them have now been deprecated. Please use std.format.formattedWrite instead.
  • The overload of std.exception.enforce which takes the file and line number as template arguments has been scheduled for deprecation (as it causes unnecessary template bloat). Please use the overload which takes them as function arguments instead. This will have no effect on any calls to enforce which do not explicitly pass the file or line number.
  • std.format.FormatError - which was scheduled for deprecation - has been deprecated. Please catch FormatException instead.
  • std.file.listDir has been deprecated. Please use std.file.dirEntries instead.
  • std.range.replicate - which was scheduled for deprecation - has been deprecated. Please use repeat instead.
  • std.range.SortedRange.canFind - which was scheduled for deprecation - has been deprecated. Please use SortedRange.contains instead.
  • std.socket: timeval and linger - which were scheduled for deprecation - have been deprecated. Please use TimeVal and Linger.
  • std.stdio.isStreamingDevice has been scheduled for deprecation. Please use isFileHandle instead.
  • The deprecated std.typecons.defineEnum has been removed.
  • UtfException - which was scheduled for deprecation - has been deprecated. Please use UTFException instead.
  • The deprecated overloads of std.array.insert and std.array.replace have been removed. Please use insertInPlace and replaceInPlace instead.
  • The deprecated toISOExtendedString and fromISOExtendedString functions in std.datetime have been removed. Please use toISOExtString and fromISOExtString instead.
  • The deprecated std.file.getTimesPosix has been removed. Please use std.file.getTimes instead.
  • The deprecated overloads of isFile, isDir, and isSymLink in std.file which took uint have been removed. Please use attrIsFile, attrIsDir, and attrIsSymlink instead.
  • The deprecated std.file.DirEntry.timeStatusChanged has been removed. Please use std.file.DirEntry.attributes to get at that information if you need it.
  • The deprecated std.contracts module has been removed. Please use std.exception instead.
  • The deprecated std.arg, std.bind, and std.loader modules have been removed.
  • Added TypeInfo.rtInfo property to get library defined runtime info.
  • Added front end support for AVX 256 bit SIMD instructions.
  • Default arguments and parameter identifiers (if any) are added to the tuple generated from IsExpression's __parameters case.
  • Changed the way the align attribute works, to make it more usable and comprehensible. Default alignment has not changed.
  • The align attribute now accepts arbitrary powers of two. This affects layout of static data, too. Such effects are dependent on limitations of the object file format - currently Win32 programs cannot align on larger than 16 byte boundaries.
  • HTML input file support completely removed.
  • Bugzilla 3150: cast from dynamic array to ulong is allowed
  • Bugzilla 3866: anonymous delegate with default parameters cross-talks to another anonymous delegate
  • Bugzilla 4174: Template interface functions not allowed, making operator overloads difficult
  • Bugzilla 6652: 1. Warn modifying non ref variable if -w is specified.
  • Bugzilla 7243: Compiler should call separate function when allocating a struct on the heap
  • Bugzilla 7923: Please remove 'deprecated' from setAssertHandler()
  • Bugzilla 8105: in ref
  • Bugzilla 8127: dmd link library paths not given precedence over gcc defaults
  • Bugzilla 8221: typeof(null) rejected as return type for covariant overrides

Druntime Bugs Fixed

  • Bugzilla 6909: incorrect definition of the OVERLAPPED struct in core.sys.windows.windows ?

Library Bugs Fixed

  • Bugzilla 2328: setTypeInfo in gc.d backwards.
  • Bugzilla 2588: std.signals should not use 'length' stealth keyword in indexing
  • Bugzilla 4405: all function - returns whether predicate is true for all elements in a range
  • Bugzilla 4603: array(iota(1, 0)) error
  • Bugzilla 4605: Wrong print of an int[string] aa
  • Bugzilla 4629: BufferedFile.printf() wants char[] as first argument
  • Bugzilla 4695: std.range.zip is broken
  • Bugzilla 4744: std.conv: string->enum doesn't look for longer match
  • Bugzilla 4822: Problem with std.stdio.File.writef("%c")
  • Bugzilla 5011: std.container: SList linearRemove produces wrong results
  • Bugzilla 5089: feqrel does not compile for floats
  • Bugzilla 5260: std.math.feqrel() returns negative number
  • Bugzilla 5346: instantiation of std.conv.toImpl and std.format.formatValue fails for unions
  • Bugzilla 5354: formatValue: range templates introduce 3 bugs related to class & struct cases
  • Bugzilla 5786: std.algorithm.sort does not work with std.container.Array: Range violation
  • Bugzilla 5843: Unable to convert a struct with an alias-this to long/ulong to int, using std.conv.to!int.
  • Bugzilla 5970: fix BigInt.toString
  • Bugzilla 6027: bigint to!string conversion and its implications
  • Bugzilla 6175: String corruption when passing static char arrays to std.conv
  • Bugzilla 6191: removechars doesn't accept a const string
  • Bugzilla 6197: std.traits.isImplicitlyConvertible returns some wrong results.
  • Bugzilla 6222: A problem with iota() using size_t
  • Bugzilla 6231: [patch] std.conv.to/std.format.: Structs with toString and isInputRange match multiple templates.
  • Bugzilla 6273: Tuple [] operator in pure function
  • Bugzilla 6379: std.container.SList fails to compile
  • Bugzilla 6437: Refcounted calls dtor before ctor, never calls dtor for globals
  • Bugzilla 6547: Call to std.algorithm.remove causes compile error
  • Bugzilla 6580: scoped classes are aligned incorrectly
  • Bugzilla 6597: to!SomeString should use std.format.formatValue
  • Bugzilla 6642: SysTime should not be hasUnsharedAliasing
  • Bugzilla 6892: Formatted write with specified length of enum member
  • Bugzilla 6926: std.process.system return wrong exit code
  • Bugzilla 7022: File.byLine doesn't release file handle
  • Bugzilla 7138: Can't call array() on dirEntries
  • Bugzilla 7317: writeln cannot handle alias this of array type
  • Bugzilla 7326: write interprets enum with byte backing type as a character
  • Bugzilla 7348: to!string(null) matches more than one template declaration
  • Bugzilla 7356: Implement KeyType, ValueType for hashes in std.traits
  • Bugzilla 7360: Predicate templates in std.traits should consider alias this
  • Bugzilla 7515: The new std.string.translate is slow for ASCII text
  • Bugzilla 7537: `File.tmpfile` requires administrator rights on Windows
  • Bugzilla 7561: std.net.curl broken
  • Bugzilla 7660: toImpl conflict in std.conv
  • Bugzilla 7796: std.typecons.Unique is using writeln without importing std.stdio
  • Bugzilla 7824: isInputRange fails to recognize inout(T)[]
  • Bugzilla 7831: Unlisted @@@BUG in File.detach causes FILE* leaks when reopening
  • Bugzilla 7878: A problem with purity and general templated algorithms
  • Bugzilla 7898: [CTFE] std.algorithm:copy fails when used with two arrays
  • Bugzilla 7909: to!(enum)(string) and to!(string)(enum) break when enum is integral
  • Bugzilla 7919: Sample code works on GDC but fails with DMD
  • Bugzilla 7936: std.random.randomSample always returns the same first value when passed a random number generator
  • Bugzilla 7937: Range iota.Result should be const where possible
  • Bugzilla 7944: std.range.iota.popFront() cycles when the range is empty
  • Bugzilla 7948: std.range.zip broken with requireSameLength
  • Bugzilla 7962: std.regex: Captures.length() returns incorrect value
  • Bugzilla 7973: BigInt %= long/ulong gives wrong value
  • Bugzilla 7975: Incorrect quotes escaping in std.format
  • Bugzilla 7982: iota broken when start and end are unsigned and step is negative.
  • Bugzilla 7993: BigInt divide-by-1 error
  • Bugzilla 8003: Phobos uses deprecated std.path sep symbol
  • Bugzilla 8011: BigInt ++ and -- do wrong thing on negative numbers
  • Bugzilla 8015: std.typecons.Tuple does not support struct with alias method this
  • Bugzilla 8022: BigInt division bug (2)
  • Bugzilla 8026: Fix or disallow randomShuffle() on fixed-sized arrays
  • Bugzilla 8031: If a class have some signals it's impossible for a derived class to have any signals
  • Bugzilla 8037: hasElaborateDestructor is false for non-zero-length static array of structs with elaborate destructor
  • Bugzilla 8039: `scoped` doesn't call any elaborate destructors for struct fields
  • Bugzilla 8040: writeln(null) too
  • Bugzilla 8055: [Regression 2.059] std.algorithm.move corrupts moved object field
  • Bugzilla 8057: std.algorithm.move cannot use for nested struct
  • Bugzilla 8080: 'alias this' causes toString to be shadowed by aliased object
  • Bugzilla 8112: std.algorithm.fill must accept InputRange
  • Bugzilla 8158: std.algorithm.min fails to compile with user-defined types
  • Bugzilla 8164: BigInt from char[] too
  • Bugzilla 8165: BigInt opAssign return value
  • Bugzilla 8171: [Regression 2.060head] Broken std.algorithm.move for nested struct has no member
  • Bugzilla 8186: Formatting class object has an alias this to int* field is broken.
  • Bugzilla 8187: replaceFirst doesn't work for string[] haystack
  • Bugzilla 8191: cstream.printf is completely unusable on x86_64
  • Bugzilla 8195: Segfault when comparing a VariantN to a non-variant type which it holds
  • Bugzilla 8203: Use of std.regex.match() generates "not enough preallocated memory" error
  • Bugzilla 8214: blocking option for TaskPool.finish()
  • Bugzilla 8233: std.array.array fails to compile with ranges of immutable elements which have a length property
  • Bugzilla 8240: std.algorithm.joiner and empty inputRangeObject
  • Bugzilla 8264: [std.conv.to] constructing conversion doesn't work with alias this
  • Bugzilla 8310: writeln of Range of fixed size array
  • Bugzilla 8323: std.string.chompPrefix does not handle differing string types properly
  • Bugzilla 8362: std.traits.isSafe doesn't work with unsafe lamdba functions
  • Bugzilla 8386: writeln stopped working with wstring
  • Bugzilla 8398: enforceEx cannot be used with OutOfMemoryError
  • Bugzilla 8450: std.traits.isSafe doesn't work with unsafe lamdba functions

DMD Bugs Fixed

  • Bugzilla 1175: nested class inheritance
  • Bugzilla 1780: Type tuple deduction failure for class templates
  • Bugzilla 2472: Delegates are not lvalue.
  • Bugzilla 2962: ICE(glue.c) or bad codegen passing variable as template value parameter
  • Bugzilla 3290: accepts-invalid: non-const by-ref foreach over a const array is accepted
  • Bugzilla 3574: post-condition in void main() is not evaluated if there is no return statement
  • Bugzilla 3608: Allow isExpression and templates to capture template parameters and FQN of template
  • Bugzilla 3703: static array assignment
  • Bugzilla 3895: Appending a double[] to a float[] generates wrong code
  • Bugzilla 4024: Last catch only accepts block statement
  • Bugzilla 4155: return of NaN to temporary fails equality test
  • Bugzilla 4288: Error on passing delegate to C linkage function
  • Bugzilla 4364: ICE(class.c) compiling a struct def named 'Object' followed by a class definition
  • Bugzilla 4510: [tdpl] ref with a wrong type specifier is accepted
  • Bugzilla 4583: PIC code not working: EBX register set incorrectly
  • Bugzilla 4785: auto return of a function with in contract
  • Bugzilla 4884: Using template struct parameters in method definition fails with "parameter _param_0 is already defined"
  • Bugzilla 4953: Regression(2.031): templates don't do implicit conversion properly
  • Bugzilla 4967: member default initializers not working in static struct initializers
  • Bugzilla 5039: Cannot use invariant() with auto methods
  • Bugzilla 5082: delegate alias parameters are silently accepted inside structs. limits most of std.algorithm, etc.
  • Bugzilla 5435: Static foreach over tuple ignores type annotation
  • Bugzilla 5437: Problems with length of std.traits.EnumMembers
  • Bugzilla 5473: Members of const-qualified classes are not const themselves.
  • Bugzilla 5737: postblit not called for locals initialized from ref functions
  • Bugzilla 5809: [64 bit] wrong code for *p==0, when widening conversion occurs
  • Bugzilla 5896: const overload matching is succumb to template parameter one
  • Bugzilla 6189: [64bit] optimizer: register content destroyed in function prolog
  • Bugzilla 6199: [GSoC] Postblit not called when returning a reference to a by-value function
  • Bugzilla 6470: postblits not called on arrays of structs
  • Bugzilla 6475: template identifier is not a member of alias
  • Bugzilla 6591: di header generation loses selective import symbols
  • Bugzilla 6612: Associative arrays with associative array keys literals
  • Bugzilla 6636: Destructors of static array elements are not called on function parameter
  • Bugzilla 6637: Postblits of static array elements are not called on function argument
  • Bugzilla 6758: std.c.stdarg problems with 8 or more integer arguments on x86_64
  • Bugzilla 6891: template with uint value parameter causes several issues
  • Bugzilla 7396: Indicate default alignment with 0.
  • Bugzilla 7385: Bad error message missing line number on invalid array op that isn't special cased
  • Bugzilla 7413: Vector literals don't work
  • Bugzilla 7414: Vector literal assignment doesn't work in global scope
  • Bugzilla 7418: Overloading doesn't work with aliases declared inside templates
  • Bugzilla 7453: Can't return value from within opApply
  • Bugzilla 7478: stack overflow compiling with -deps -release -inline -noboundscheck
  • Bugzilla 7494: Selective import does not work inside a function
  • Bugzilla 7506: Postblit does not called properly with inlining
  • Bugzilla 7530: Postblit not called structs returned from an array index expr.
  • Bugzilla 7560: Base class overloaded methods created by mixins can't be overriden
  • Bugzilla 7581: Compiler uses wrong instructions to move complex value from ST to xmm registers
  • Bugzilla 7585: functions in templates inferred as delegate
  • Bugzilla 7750: while(true) loop with try/catch block causes segfault
  • Bugzilla 7770: __dollar cannot be read at compile time
  • Bugzilla 7784: ICE with self-referencing literals
  • Bugzilla 7793: static assert( void_function() ) gives misleading error message
  • Bugzilla 7807: Ambiguous virtual function error on const overloading with covariant return types
  • Bugzilla 7851: Internal error: e2ir.c 688
  • Bugzilla 7880: [CTFE] cast from void array allowed with different results than at runtime
  • Bugzilla 7893: Spec completely wrong for D variadic arguments on 64 bits
  • Bugzilla 7894: [CTFE] - goto within ForStatement restarts loop
  • Bugzilla 7906: [ICE] enum declaration with invalid array literal crashes dmd
  • Bugzilla 7907: [ICE] invalid expression on template argument crashes dmd
  • Bugzilla 7911: Nested static if failing to execute
  • Bugzilla 7922: alias this causes weird formatting issues for strings
  • Bugzilla 7929: Broken semantic of StructInitializer with const
  • Bugzilla 7931: Error message with _error_ with var[1,2]
  • Bugzilla 7932: Corrupted argument inside out contract in x86_64
  • Bugzilla 7933: Illegal interaction of templates
  • Bugzilla 7941: Regression(2.059): Type check is ignored when manifest constant initializer is function literal
  • Bugzilla 7943: UFCS does not work with alias this
  • Bugzilla 7945: alias this doesn't work on function ref parameter
  • Bugzilla 7949: [ICE] (cgcod.c) with SIMD array
  • Bugzilla 7950: Type tuples are incorrectly flattened in base type list of interface
  • Bugzilla 7951: DMD: Internal error: backend/cgxmm.c 567
  • Bugzilla 7965: Invalid outer function scope pointer in some cases
  • Bugzilla 7974: forward reference of mixin declaration
  • Bugzilla 7983: ICE with getMember on a unittest member
  • Bugzilla 7987: [CTFE] cannot compare arrays of slices
  • Bugzilla 8002: Excess initial errors when passing template args to non-templated struct
  • Bugzilla 8004: Direct call of function literal should consider default arguments
  • Bugzilla 8005: Lambda with parameter type inference should consider default args
  • Bugzilla 8016: Methods defined in external object files when template alias parameter is involved
  • Bugzilla 8032: `mixin template` before virtual method with same method causes an error
  • Bugzilla 8036: Zero-length static array of structs with elaborate destructor as struct or class field is rejected
  • Bugzilla 8038: #line which is in a double template instantiation doesn't work
  • Bugzilla 8060: xmmstore cannot allocate store for optimized operation that uses int and floats
  • Bugzilla 8064: return reference semantics not obeyed on delegates?
  • Bugzilla 8066: ICE on missing return statement if invariant is present
  • Bugzilla 8069: incorrect ambiguous virtual function error
  • Bugzilla 8073: Regression (git) Error: undefined identifier __result
  • Bugzilla 8089: Importing package as module causes segfault
  • Bugzilla 8091: Optimizer generates wrong code when reducing comparisons
  • Bugzilla 8094: Static if matching using alias parameter in template fails
  • Bugzilla 8095: [64 bit] Wrong code generation with spilled register, -m64 -O
  • Bugzilla 8098: Inner class method can modify outer's members regardless of constancy
  • Bugzilla 8099: Inner class's outer pointer matches constancy of inner, but can be set to object of arbitrary constancy
  • Bugzilla 8182: with a lazy struct parameter, the struct's destructor is called on the generated delegate
  • Bugzilla 8180: UFCS writeln doesn't work with Tuples
  • Bugzilla 8113: alias this doesn't forward opCall
  • Bugzilla 8123: alias declaration lookup is broken
  • Bugzilla 8125: TypeInstance dedunction problem
  • Bugzilla 8129: Cannot deduce template function when using partially specified type in function parameter
  • Bugzilla 8147: Blah!R.init now requires parens - (Blah!R).init
  • Bugzilla 8168: dmd crashes when asm statement with wrong opcode
  • Bugzilla 8169: Method loses its compile-time evaluability when used through alias this
  • Bugzilla 8185: Pure functions and pointers
  • Bugzilla 8188: need this to access member when mixining in a function
  • Bugzilla 8190: Externally defined struct error message
  • Bugzilla 8194: "Function cannot access frame" even though all I requested was the type
  • Bugzilla 8198: Nested lambda inference doesn't work
  • Bugzilla 8199: stack is not aligned in finally block
  • Bugzilla 8212: shared value data structures should implicitly cast to mutable
  • Bugzilla 8216: CTFE should allow 'pointer is inside range' comparisons
  • Bugzilla 8226: Global lambda assign to const/immutable
  • Bugzilla 8237: Error message with _error_ when using failed type inference in template parameter
  • Bugzilla 8241: cannot use template function literal as default alias argument
  • Bugzilla 8242: cannot use template function literals at module scope
  • Bugzilla 8249: Spurious error message with templates and alias this
  • Bugzilla 8252: no UFCS for 0 literal
  • Bugzilla 8276: [CTFE] ICE when reading variable from nested function
  • Bugzilla 8283: ICE(cod1.c): returning struct with constructor as member of another struct
  • Bugzilla 8315: Invalid nested-ref check in template constraint
  • Bugzilla 8335: `ref` is ignored for static array of stucts with postblit argument
  • Bugzilla 8390: Refused array operation mutable[] += const[]
  • Bugzilla 8397: parameter types are not checked when assigning a function literal
  • Bugzilla 8423: Wrong code for bool parameter in 5th integer register.
  • Bugzilla 8429: [2.060 beta] 'version' rejected inside 'static if's
  • Bugzilla 8434: [Regression 2.058] cannot implicitly convert expression (vs1.opCast()) of type const(Vector2D) to object.Object
  • Bugzilla 8437: [2.060 beta] static struct no size yet for forward reference
  • Bugzilla 8442: [2.060 beta] Empty array enum not treated as immutable
  • Bugzilla 8453: Associative array keys refused as property by sort
  • Bugzilla 8454: [ICE] (backend\cg87.c 3497) with cdouble and sqrt
Version D 2.059 Apr 12, 2012

New/Changed Features

  • Add predefined Ddoc macro SRCFILENAME
  • Changed lexer to support # as a token, preserving #line's original behavior
  • added AES, PCLMULQDQ, RDRAND, AVX, VAES, VPCLMULQDQ, FMA, FP16C to core.cpuid
  • Bugzilla 435: Constructors should be templatized
  • Bugzilla 2367: Overloading error with string literals
  • Bugzilla 3382: [tdpl] Implement uniform function call syntax
  • Bugzilla 4536: Typetuples (T...) should have an .init member
  • Bugzilla 5525: Eponymous templates should allow for overloaded eponymous members
  • Bugzilla 7105: relax inout rules
  • Bugzilla 7833: Changelog should clearly mention struct literal/opCmp/opEquals/toHash changes
  • Strive to make toHash, toString, opEquals and opCmp functions pure, nothrow, const and @safe. Soon, this will become a requirement.
  • The deprecated std.date, std.dateparse, and std.gregorian modules have been removed. Please use std.datetime instead.
  • Several deprecated functions in std.file have been removed.
  • The old functions in std.path which were scheduled for deprecation have now been deprecated. Please use the new ones which were introduced in 2.055. However, note that curdir and pardir do not have replacements, because they're "." and ".." respectively on all OSes so variables for them were seen as unnecessary. Also, one major change to note about the new std.path functions is that when operating on extensions, they expect "." to be part of the extension whereas the old ones did not (e.g. "file.txt".extension == ".txt" whereas "file.txt".getExt() == "txt").
  • The version of std.exception.enforceEx which was scheduled for deprecation has been deprecated. Please use the version which takes exceptions which can be constructed with new E(msg, file, line) (rather than just new E(msg) as the old version did). That way, exceptions constructed with enforceEx will give the file and line number where enforceEx was called.
  • Get rid of Win9x support.
  • std.typecons: Added Proxy mixin template.
  • std.format: Added documentation about compound format specifier.

Druntime Bugs Fixed

Library Bugs Fixed

  • Bugzilla 4604: A stack overflow with writeln
  • Bugzilla 5523: std.regex handles "\s" and "\W" (etc.) inside square brackets improperly
  • Bugzilla 5652: Add \p and \P unicode properties to std.regex
  • Bugzilla 5674: AssertError in std.regex
  • Bugzilla 5964: std.stdio.readln can throw a UnicodeException
  • Bugzilla 6217: [GSOC] result of std.algorithm.map is not movable
  • Bugzilla 6403: Upgrade std.regex to Unicode UTS #18 Level 1 support
  • Bugzilla 6892: Formatted write with specified length of enum member
  • Bugzilla 7111: New regex engine cannot match beginning of empty string
  • Bugzilla 7138: Can't call array() on dirEntries
  • Bugzilla 7264: Can't iterate result from 4-arg dirEntries as string
  • Bugzilla 7299: std.uni missing doc comments
  • Bugzilla 7300: std.regex.ShiftOr!dchar.search is broken
  • Bugzilla 7374: stdin.byLine() throws AssertError on empty input
  • Bugzilla 7460: std.windows.registry reports a false exception message
  • Bugzilla 7476: Write(ln) functions no longer accept retro range
  • Bugzilla 7628: std.format formatValue incorrect overload
  • Bugzilla 7674: regex replace requires escaped format
  • Bugzilla 7679: std.regex.split and splitter don't work w/ ctRegex
  • Bugzilla 7718: regex and ctRegex produce different results

DMD Bugs Fixed

  • rdmd: --force now works with --eval
  • rdmd: update --eval's import list
  • Bugzilla 176: [module] message "module and package have the same name"
  • Bugzilla 783: Cannot use an array w/ const or variable index as new[] size argument.
  • Bugzilla 977: Expressions inside a struct or array initializer get wrong line number
  • Bugzilla 3279: Confusing error message when comparing types
  • Bugzilla 3354: invalid number of args accepted for 1/2 arg floating point instructions
  • Bugzilla 3509: Cannot forward reference a template mixin's members in a compile-time context
  • Bugzilla 3510: Cannot forward reference a templated type from within a template mixin
  • Bugzilla 3559: DMD 1.048+ fails to take function pointer from overloaded member functions
  • Bugzilla 3630: bad error location in "has no effect in expression" error
  • Bugzilla 3682: Regression(2.038) is expression fails to match types
  • Bugzilla 3812: Missing line number for implicit cast of variadic function to array
  • Bugzilla 3822: Invalid optimization of alloca called with constant size
  • Bugzilla 3927: array.length++; is an error, but ++array.length compiles
  • Bugzilla 4241: duplicate union initialization error doesn't give a file location
  • Bugzilla 4269: Regression(2.031): invalid type accepted if evaluated while errors are gagged
  • Bugzilla 4507: use spellchecker when override function doesn't override anything
  • Bugzilla 4820: Regression(1.058, 2.044) in DStress caused by changeset 452
  • Bugzilla 4854: Regression(2.047, Mac 10.5 only) writefln Segmentation fault if no globals
  • Bugzilla 4993: Temporary values and opIndexAssign
  • Bugzilla 5181: Excess cast on in-place operation op= involving conversion
  • Bugzilla 5412: import wtf2
  • Bugzilla 5554: [qtd] Covariance detection failure
  • Bugzilla 5590: Regression(2.036) ICE(e2ir.c): when using .values on enum which is associative array
  • Bugzilla 5733: Calling opDispatch As Template Results in Compiler Infinite Loop
  • Bugzilla 5879: Not all frontend errors use stderr
  • Bugzilla 5889: Struct literal/construction should be rvalue (it binds to ref parameters)
  • Bugzilla 6391: Line-less error when passing the '.im' of floating pointer value by reference
  • Bugzilla 6438: [CTFE] wrong error "value used before set" when slicing =void array
  • Bugzilla 6611: better error message for array post increment/decrement
  • Bugzilla 6681: struct constructor call is converted to struct literal that breaks union initialization
  • Bugzilla 6685: Allow using "with" with rvalues
  • Bugzilla 6699: More cases of __error in error messages
  • Bugzilla 6738: Can't call templatized property function from within a struct/class method
  • Bugzilla 6785: Wrong error message from pragma(msg) of failed instantiation
  • Bugzilla 6982: immutability isn't respected on associative array assignment
  • Bugzilla 7038: Type mismatch with const struct
  • Bugzilla 7110: opSlice() & opIndex functions works unstable as template arguments
  • Bugzilla 7288: ICE(toir.c): with lambda return + auto
  • Bugzilla 7353: NRVO not properly working with inferred return type
  • Bugzilla 7380: Crash trying to use address of variable in struct constructor at module level
  • Bugzilla 7399: Broken import statement in trySemantic() causes silent compiler error
  • Bugzilla 7406: tuple foreach doesn't work with mixed tuples
  • Bugzilla 7411: Deduce base type from vector types in templates
  • Bugzilla 7439: Compound assignment causes segmentation fault
  • Bugzilla 7452: Function using enforce() cannot be inferred as @safe because of anonymous function due to lazy argument
  • Bugzilla 7462: Error message with _error_ in overridden function
  • Bugzilla 7463: Duplicated error message with bad template value parameter
  • Bugzilla 7473: [CTFE] Non-ref argument behaves as if it's a ref argument
  • Bugzilla 7481: Compiler should 'soldier on' after template errors
  • Bugzilla 7493: Initialization of void[][N]
  • Bugzilla 7499: ICE(cast.c line 1495) with lambda array
  • Bugzilla 7500: [ICE] (template.c line 5287) with immutable lambda function
  • Bugzilla 7502: 2.056 regression: Assigning .init takes forever to compile for large structs
  • Bugzilla 7504: Cannot assign an object of type 'typeof(null)' to an array
  • Bugzilla 7518: std.array.empty doesn't work for shared arrays
  • Bugzilla 7525: [2.058 regression] Broken return type inference for delegate returns
  • Bugzilla 7527: [CTFE] Segfault when slicing a pointer at compile time
  • Bugzilla 7536: ctfeAdrOnStack triggered
  • Bugzilla 7544: ICE(interpret.c) Catching an exception with a null catch block
  • Bugzilla 7545: ICE(cast.c) Merge integral types through alias this
  • Bugzilla 7547: -deps output lists object as a top level module
  • Bugzilla 7550: Missing AVX instruction VPMULDQ
  • Bugzilla 7552: Cannot get and combine a part of overloaded functions
  • Bugzilla 7554: Immutable function pointer arguments too
  • Bugzilla 7557: Sea of errors after template failure
  • Bugzilla 7562: DMD crashes by using TemplateThisParameter
  • Bugzilla 7563: Class members with default template arguments have no type
  • Bugzilla 7568: pragma(msg) segfaults with an aggregate including a class.
  • Bugzilla 7578: ICE on indexing result of vararg opDispatch
  • Bugzilla 7580: Identity assignment of Nullable crashes dmd
  • Bugzilla 7582: Untyped nested delegate literals don't compile
  • Bugzilla 7583: [CTFE] ICE with tuple and alias this
  • Bugzilla 7589: __traits(compiles) does not work with a template that fails to compile
  • Bugzilla 7592: Conversion from ireal to ifloat broken when using xmm
  • Bugzilla 7595: Data being overwritten.
  • Bugzilla 7608: __traits(allMembers) is broken
  • Bugzilla 7618: delegate/function pointer call bypass parameter storage class
  • Bugzilla 7621: Immutable type equivalence problem
  • Bugzilla 7633: Missing CTFE error message
  • Bugzilla 7639: Undefined enum AA key crashes compiler
  • Bugzilla 7641: std.typecons.Proxy incorrectly allows implicit conversion to class
  • Bugzilla 7643: Whole tuple slice isn't resolved as expected
  • Bugzilla 7649: Bad lambda inference in default function argument
  • Bugzilla 7650: Bad lambda inference in associative array literal
  • Bugzilla 7667: ICE(interpret.c): 'ctfeStack.stackPointer() == 0'
  • Bugzilla 7669: Broken inout deduction with static array type
  • Bugzilla 7670: UFCS problem with @property and structs
  • Bugzilla 7671: Broken inout deduction of shared(inout(T[n])) from immutable(int[3])
  • Bugzilla 7672: Remove top const doesn't work for inout array type.
  • Bugzilla 7681: Regression(2.059head):ICE:opCatAssign(delegate) to undefined identifier
  • Bugzilla 7682: shared array type and "cast() is not an lvalue" error
  • Bugzilla 7684: IFTI and shared overload doesn't work
  • Bugzilla 7694: Internal error: e2ir.c 1251 when calling member function inside struct via alias param
  • Bugzilla 7695: Regression(2.058): ICE(mtype.c) on associative array with keys of struct type with const members
  • Bugzilla 7698: can't specialize parameterized template value
  • Bugzilla 7699: Cannot get frame pointer to in contract when compiling with -inline
  • Bugzilla 7702: opDispatch goes into infinite loop
  • Bugzilla 7703: [UFCS] explicit template function instantiation as property
  • Bugzilla 7705: lambda syntax doesn't allow some valid signatures
  • Bugzilla 7713: lambda inference doesn't work on template function argument
  • Bugzilla 7722: Refuse normal functions to be used as properties
  • Bugzilla 7731: Assertion failure: 't' on line 7911 in file 'mtype.c'
  • Bugzilla 7732: [CTFE] wrong code for a struct called AssociativeArray
  • Bugzilla 7735: Functions with variadic void[][]... arguments corrupt passed data
  • Bugzilla 7742: 'More initializers than fields' error with correct number of fields
  • Bugzilla 7743: Parsing problem with nothrow delegate
  • Bugzilla 7745: Regression (1.x git-415e48a) Methods defined in external object files when a pointer to it is taken
  • Bugzilla 7751: [ICE] (Regression 2.059head) From auto and forward reference
  • Bugzilla 7754: static this() in template is stripped during header gen
  • Bugzilla 7755: regression(2.059head): ICE in glue.c
  • Bugzilla 7757: Inout function with lazy inout parameter doesn't compile
  • Bugzilla 7761: lambda expression doesn't parse attributes
  • Bugzilla 7768: More readable template error messages
  • Bugzilla 7769: relax inout rule doesn't work for template function
  • Bugzilla 7722: Refuse normal functions to be used as properties
  • Bugzilla 7773: UCFS syntax on built-in attributes too?
  • Bugzilla 7781: [CTFE] Segmentation fault on 'mixin({return;}());
  • Bugzilla 7782: [ICE] With wrong import syntax
  • Bugzilla 7785: [CTFE] ICE when slicing pointer to variable
  • Bugzilla 7786: dmd crashes with invalid module name
  • Bugzilla 7789: [CTFE] null pointer exception on setting array length
  • Bugzilla 7794: Sea of errors when calling regex() after compile error
  • Bugzilla 7808: Nullable's alias this does not work with structs containing classes
  • Bugzilla 7812: Segfault on invalid code during template match deduction with errors gagged
  • Bugzilla 7814: Regression(2.059head) ICE(tocsym.c) using scope(failure) within foreach-range
  • Bugzilla 7815: Mixin template forward reference (?) regression
  • Bugzilla 7820: regression(DMD 2.059head) Wrong error on forward reference to 'front' with -property switch
  • Bugzilla 7823: Can't use a struct initializer to initialize a nested enum used as a default function argument initializer
  • Bugzilla 7826: [D2 Beta] Cannot use getHash in toHash without a warning
  • Bugzilla 7843: Regression(2.059 beta): Informational warning fails to produce executable
  • Bugzilla 7857: File#write formats enum as a boolean.
  • Bugzilla 7858: __traits(getOverloads) returns incorrect symbol
  • Bugzilla 7859: Crash on invalid alias template parameter type
  • Bugzilla 7861: Segfault during __error propagation with self-referencing module
  • Bugzilla 7862: Accepts-invalid template forward reference bug related to derivedMembers
  • Bugzilla 7868: derivedMembers/static if regression
  • Bugzilla 7869: Cannot format pointer of struct has toString member function
  • Bugzilla 7871: RangeViolation with findSplitBefore
  • Bugzilla 7873: [2.059 beta] IFTI with inout does not properly match template parameter if called from inout function for pointers
  • Bugzilla 7886: derivedMembers infinite recursion
  • Bugzilla 7888: derivedMembers forward reference error with nested imports
Version D 2.058 Feb 14, 2012

New/Changed Features

  • Add new => lambda syntax.
  • Allow 1.userproperty syntax. NOTE: 1.f is no longer a float literal, add a 0.
  • Convert to -shared dmd switch instead of -dylib
  • Better use of XMM registers in OS X 32 bit target.
  • Add inline assembler support for AVX instructions (64 bit targets only).
  • Use of base class protection is now deprecated.
  • Added traits isVirtualMethod and getVirtualMethods.
  • Struct/class invariants are now implicitly const.
  • Major overhaul of std.regex module's implementation. Breaking change in std.regex.replace with delegate, use Captures!string instead of RegexMatch!string as delegate parameter.
  • As typedef has been deprecated, overloads of std.conv.to which use typedef have now been deprecated.
  • std.array.insert has been deprecated. Please use std.array.insertInPlace instead.
  • The overload of std.array.replace which replaces in place has been deprecated. Please use std.array.replaceInPlace instead.
  • The toISOExtendedString and fromISOExtendedString functions on SysTime, Date, TimeOfDay, and DateTime in std.datetime have been deprecated. Please use toISOExtString and fromISOExtString instead.
  • std.file.getTimesPosix has been deprecated. Please use std.file.getTimes instead.
  • The overloads for isDir, isFile, and isSymlink in std.file which take a uint have been deprecated. Please use attrIsDir, attrIsFile, and attrIsSymlink instead.

Druntime Bugs Fixed

Library Bugs Fixed

  • Bugzilla 4295: IID_IUnknown symbol undefined in phobos.lib
  • Bugzilla 7241: std.format can't read into array of dchar

DMD Bugs Fixed

  • Bugzilla 516: Mutually calling constructors allowed
  • Bugzilla 620: Can't use property syntax with a template function
  • Bugzilla 664: is(func T == function) ignores variadic arguments
  • Bugzilla 678: Compiler accepts, for a function T[] t(), t().ptr but not t.ptr
  • Bugzilla 796: Asserting a null object reference throws AssertError Failure internal\invariant.d(14) or Access Violation
  • Bugzilla 949: Wrong spec/compiler behaviour for Strings, Integers and Floats
  • Bugzilla 955: Passing arguments into functions - in, out, inout, const, and contracts
  • Bugzilla 1313: out/body disables escape analysis
  • Bugzilla 1521: Ambiguous documentation
  • Bugzilla 1563: dynamic cast is not always performed
  • Bugzilla 1570: Wrong return for address operator
  • Bugzilla 1918: __traits(getVirtualFunctions) returns final functions
  • Bugzilla 1920: Class documentation incomplete
  • Bugzilla 1943: Templates can't take function pointer parameters
  • Bugzilla 2106: export class doesn't affect, what is exported
  • Bugzilla 2351: enum with no members allowed
  • Bugzilla 2382: spec is not clear on what is allowed as global/static initializers
  • Bugzilla 2387: Static array terminology
  • Bugzilla 2411: Reference Tuple Foreach
  • Bugzilla 2417: [module] protected base member is not available via base handle in a derived class if it is defined in a separate module
  • Bugzilla 2442: opApply does not allow inferring parameter types when overloaded on const
  • Bugzilla 2443: opApply should allow delegates that are not ref if it makes no sense
  • Bugzilla 2483: DMD allows assignment to a scope variable
  • Bugzilla 2494: describe explicit casting of arrays
  • Bugzilla 2495: const syntax for member functions needs better description
  • Bugzilla 2497: delete and null relationship needs more details
  • Bugzilla 2524: final override inconsistent when implementing interfaces
  • Bugzilla 2639: Hex and octal string values not completely specified
  • Bugzilla 2819: array.sort segfaults if array length >=0x8F_FFFF
  • Bugzilla 2894: abstract classes sometimes allow non-abstract bodyless functions
  • Bugzilla 2997: allMembers does not return interface members
  • Bugzilla 3084: Formatting of lazy in parameters section
  • Bugzilla 3092: Indexing a tuple produces a tuple containing the indexed element
  • Bugzilla 3111: 'mangleof' can't be member of a struct not documented
  • Bugzilla 3187: Nested foreach over opApply doesn't work
  • Bugzilla 3204: Document global properties
  • Bugzilla 3235: [tdpl] Function literals must be deduced as "function" or "delegate"
  • Bugzilla 3265: .classinfo for Interface-typed reference does not return instance's ClassInfo
  • Bugzilla 3492: Can't overload nested functions
  • Bugzilla 3578: Impossible to run a struct invariant using assert(s)
  • Bugzilla 3735: op=
  • Bugzilla 3757: Overloading const function with overridden non-const function results in seg fault.
  • Bugzilla 3777: size_t is undefined
  • Bugzilla 3783: Text inconsistent with EscapeSequence rules
  • Bugzilla 3787: clarification: assigment to 'this'
  • Bugzilla 3791: Reference anonymous nested classes when describing new expressions
  • Bugzilla 3800: "Foreach over Structs and Classes with Ranges" and "Invariant Struct" in D2 Spec
  • Bugzilla 3838: PrimaryExpression rule doesn't permit module scope template instances
  • Bugzilla 3886: Bad example of definition file for DLLs
  • Bugzilla 3906: Undefined struct and union declarations are not documented
  • Bugzilla 3908: @ attributes not part of function grammar
  • Bugzilla 3954: DeclDef rule is missing TemplateMixinDeclaration
  • Bugzilla 3988: Provide canonical example for operator overloading
  • Bugzilla 4088: opEquals not called on interfaces
  • Bugzilla 4180: D DWARF extensions conflict with DWARF-4
  • Bugzilla 4251: Hole in the const system: immutable(T)[] implicitly casts to ref const(T)[]
  • Bugzilla 4371: segfault(template.c) template tuple in is() expression
  • Bugzilla 4413: typeof(this) doesn't work in method template signature
  • Bugzilla 4421: Union propagates copy constructors and destructors over all members
  • Bugzilla 4523: [tdpl] .remove method for Associative Arrays returns void in all cases
  • Bugzilla 4539: Refuse assignment to string literal
  • Bugzilla 4545: Alias to members possible without "this" instance
  • Bugzilla 4550: D2 Language Docs: http://www.digitalmars.com/d/2.0/statement.html
  • Bugzilla 4553: D2 Language Docs: http://www.digitalmars.com/d/2.0/struct.html
  • Bugzilla 4647: [tdpl] Cannot explicitly call final interface method, ambiguous calls allowed
  • Bugzilla 4651: Docs: Returned classes that have access to stack variables of its enclosing function
  • Bugzilla 4675: [tdpl] Eponymous Template should hide internal names
  • Bugzilla 4711: Incorrect handling of && operator with void operand
  • Bugzilla 4841: -inline wrecks nested struct with alias template parameter (An array()/map inlining problem)
  • Bugzilla 4887: Right-shifting by 32 is allowed and broken
  • Bugzilla 4940: ICE(symbol.c): Accessing tuple-typed field of struct literal with user-defined constructor
  • Bugzilla 4956: remove direct references to gcc from linux.mak
  • Bugzilla 5023: Docs about order of execution of invariant and pre/post conditions
  • Bugzilla 5111: Static function-level variables are not in the language spec.
  • Bugzilla 5114: Too many error messages
  • Bugzilla 5132: ~ unary operator silently different from C
  • Bugzilla 5138: Special token sequence
  • Bugzilla 5261: Uncompilable example for Windows
  • Bugzilla 5299: Protected inheritance is semantically undefined.
  • Bugzilla 5337: Documentation regarding interfacing with C does not account for TLS differences
  • Bugzilla 5476: spec: attributes have an optional else clause
  • Bugzilla 5493: Able to overwrite immutable data by passing through ref function parameter
  • Bugzilla 5527: Bug in http://www.digitalmars.com/d/2.0/ctod.html#closures
  • Bugzilla 5605: [tdpl] foreach with ranges doesn't support opSlice()
  • Bugzilla 5648: dmd command line option list inconsistencies
  • Bugzilla 5713: Broken final switch on ints
  • Bugzilla 5715: Contradiction in spec: meaning of variable.init
  • Bugzilla 5718: Can't demangle symbol defined inside unittest block
  • Bugzilla 5796: ICE with pragma(msg, ...) after missing ';' in a template
  • Bugzilla 5820: Documentation states string literals can implicitly convert to char*
  • Bugzilla 5841: alias grammar is incorrect
  • Bugzilla 6013: private ignored for aliases
  • Bugzilla 6037: [CTFE] recursive ref parameters evaluated incorrectly
  • Bugzilla 6091: [d-p-l.org] Description for "Modifier casting" is misleading
  • Bugzilla 6165: Anonymous enums specification
  • Bugzilla 6177: Regression(2.053): ICE backend/cgcs.c: struct with destructor in assoc. array or typesafe variadic functions
  • Bugzilla 6205: Strongly-pure nothrow functions with ignored return value are entirely stripped even if it contains a failing 'assert'.
  • Bugzilla 6208: Parameter storage classes are ignored in template function deducing.
  • Bugzilla 6364: Static struct's destructor called on exit of function
  • Bugzilla 6402: Note on @property in spec needs updating
  • Bugzilla 6451: [64bit] ICE(expression.c:4434): SymbolExp::SymbolExp(Loc, TOK, int, Declaration*, int): Assertion 'var' failed
  • Bugzilla 6473: Stack overflow with struct destructor as default parameter
  • Bugzilla 6504: Regression(2.041): "str" ~ [arr] allows string literal to be modified
  • Bugzilla 6701: template specialization resolution failure
  • Bugzilla 6704: CommaExpression as an IfCondition
  • Bugzilla 6714: [tdpl] Type inference for parameters of function and delegate literals
  • Bugzilla 6780: Templated global property functions do not work
  • Bugzilla 6839: documentation for opAssign incorrect
  • Bugzilla 6933: Segfault(declaration.c) using struct with destructor in CTFE
  • Bugzilla 6934: [CTFE] can't use $ in a slice of an array passed by ref
  • Bugzilla 6939: wrong type qualifier combination
  • Bugzilla 6940: immutable(int*)*/immutable(int)** and int** do not combine
  • Bugzilla 6948: Possible bug in compiler or documentation regarding signature of opCmp()
  • Bugzilla 6964: Error message with __error: static assert(undefined+1)
  • Bugzilla 6968: Segmantation fault, if exclamation mark absent
  • Bugzilla 6971: [lex.dd] Type of string literals are outdated
  • Bugzilla 6984: CTFE generates a torrent of spurious errors, if there was a previous error
  • Bugzilla 6985: [CTFE] Non-constant case expressions can't be interpreted
  • Bugzilla 6987: The "Memory Management" documentation incorrectly claims arrays are passed by reference
  • Bugzilla 6995: [CTFE] can't interpret static template method
  • Bugzilla 7011: No line number error for vector power
  • Bugzilla 7037: TemplateTypeParameterSpecialization works differently from IsExpression regarding alias this
  • Bugzilla 7043: CTFE: ICE illegal reference value 0LU, only with -inline
  • Bugzilla 7073: Parsing of class-returning varargs function inside module ctor fails
  • Bugzilla 7108: ICE: TraitsExp::semantic(Scope*) 2.056 -> 2.057 regression - segfault
  • Bugzilla 7120: Scope Delegates + Delegate Literals
  • Bugzilla 7123: static assert(is(typeof(toDelegate(&main)))) is false
  • Bugzilla 7124: Alias this type is not considered in template type deduction
  • Bugzilla 7127: Const-related infinite recursion in DWARF generation
  • Bugzilla 7133: [tdpl] There should be no empty statement
  • Bugzilla 7136: alias this lookup should run before merging modifiers of both sides.
  • Bugzilla 7143: [CTFE] cannot compare class references with "is"
  • Bugzilla 7144: [CTFE] base class does not call overridden members
  • Bugzilla 7154: [CTFE] failing downcast causes error
  • Bugzilla 7158: [CTFE] ICE(interpret.c) calling a class member using a dotvar expression
  • Bugzilla 7160: Regression(2.057): ICE(dsymbol.c:1052) ICE using __traits(derivedMembers)
  • Bugzilla 7162: [CTFE] "bool || void" expression crashes dmd
  • Bugzilla 7165: [CTFE] ice converting null pointer to bool with constant member function
  • Bugzilla 7166: Internal error: ../ztc/cgxmm.c 60
  • Bugzilla 7168: Regression(2.057) __traits(allMembers) returns wrong tuple
  • Bugzilla 7170: [UFCS] array + specialized template member syntax causes ICE
  • Bugzilla 7173: dmd: glue.c:1065: virtual unsigned int Type::totym(): Assertion `0' failed.
  • Bugzilla 7178: Segfault with import of invalid template
  • Bugzilla 7185: [CTFE] ICE on changing char array length
  • Bugzilla 7187: Regression(head 12d62ca5): [CTFE] ICE on slicing
  • Bugzilla 7188: "import phobos;" crashes DMD
  • Bugzilla 7189: inline failed
  • Bugzilla 7190: Tuple length incorrect
  • Bugzilla 7193: Regression(2.058head): ICE: delete lambda expression crashes dmd
  • Bugzilla 7194: [CTFE] Incorrect behaviour with pointers as local struct variable
  • Bugzilla 7196: Unfair function address overload resolution
  • Bugzilla 7197: enum string doesn't work with CTFE
  • Bugzilla 7199: std.string.indexof cannot be compiled with -inline
  • Bugzilla 7201: Lambda template assignment to variable
  • Bugzilla 7207: Explicit cast should resolve lambda type
  • Bugzilla 7212: Regression(Head): ICE with overload resolution and delegate/function inference
  • Bugzilla 7216: [CTFE] Can't call struct member function using pointer field
  • Bugzilla 7217: [CTFE] ICE on accessing struct array field
  • Bugzilla 7218: Nested function with contract is rejected
  • Bugzilla 7228: MOVDQ2Q instruction is emitted with swapped register indices
  • Bugzilla 7231: Segfault using opDispatch with property notation
  • Bugzilla 7232: Warning: statement is not reachable has no line number
  • Bugzilla 7234: Segmentation fault when using stdio
  • Bugzilla 7239: C style struct initialization doesn't work with aliases
  • Bugzilla 7245: [CTFE] Address of ref foreach parameter changes to point after array
  • Bugzilla 7248: [CTFE] Stack overflow on using struct filed pointer with address of array element
  • Bugzilla 7261: ICE(glue.c): With taskPool.reduce
  • Bugzilla 7266: [CTFE] Assign to ref param (that's taken from struct member) is noop
  • Bugzilla 7277: [CTFE ICE] Assertion failure: 'thisval' on line 1690 in file 'interpret.c'
  • Bugzilla 7278: Templated struct (instantiated with null) can't access its own members
  • Bugzilla 7285: Implicit fixed-size array cast
  • Bugzilla 7290: Heap allocation with scoped delegate literal
  • Bugzilla 7294: [Regression] No warning when escaping local reference type variables
  • Bugzilla 7295: Alias This + Pure + pointsTo = rejects-valid
  • Bugzilla 7296: [2.058] Regression: Cannot swap RefCounted
  • Bugzilla 7309: [2.058] Regression caused by new inlining code
  • Bugzilla 7321: returning void considered unsafe by safety inference
  • Bugzilla 7335: sometimes the OUT - block have undefined class members-acces
  • Bugzilla 7351: Possible asm bug: bad type/size of operands 'xadd'
  • Bugzilla 7359: Template function with typesafe variadic rejects more than one string arguments
  • Bugzilla 7363: Eponymous Template doesn't hide internal names in some cases with `static if`
  • Bugzilla 7365: [Regression after 2.057] AAs broken for Object keys and values with opEquals
  • Bugzilla 7367: wrong char comparison result
  • Bugzilla 7369: Inout constructor causes compiler to reject invariant
  • Bugzilla 7373: (Regression git) Renamed imports conflict with other implicitly imported symbols
  • Bugzilla 7375: Regression(2.057): Invalid downcast permitted with derived/aliased template classes
  • Bugzilla 7377: Compiler segfault in: TemplateMixin::hasPointers()
  • Bugzilla 7379: DMD segfaults on semantic3 phase when alias enum this
  • Bugzilla 7383: Blank lines in code sections cause premature section termination
  • Bugzilla 7384: Typo in volatile deprecation message
  • Bugzilla 7394: ddmangle tool needs rebuilding
  • Bugzilla 7416: 2.058 regression: fails to instantiate a constrained function template with a nested function
  • Bugzilla 7419: [2.058/CTFE] Constructor of struct is overwritten inside a unittest with -inline
  • Bugzilla 7422: Regression(master): ICE with template function and if statement
  • Bugzilla 7424: Segfault when trying to call a templated property with different const-ancy.
  • Bugzilla 7425: IFTI does not work with inout methods
  • Bugzilla 7428: regression (DMD 2.058head) ICE on slightly convoluted setup including closures
  • Bugzilla 7435: Regression(master):dmd crashes when 'scope(failure) debug ...' without -debug option.
  • Bugzilla 7475: Regression(2.058 beta): Template member erroneously inaccessible
  • Bugzilla 7498: function expected before (), not function
Version D 2.057 Dec 13, 2011

New/Changed Features

  • Better use of XMM registers in 64 bit targets.
  • The invariant keyword as a synonym for immutable is now deprecated - use immutable instead
  • Add Mach-O 64 bit support for obj2asm and dumpobj
  • classes, interfaces, and exceptions are supported in CTFE
  • Bugzilla 3474: PATCH: Implement opDollar for struct and class indexing operations
  • Bugzilla 6572: Deprecate typedef
  • Major overhaul of std.regex module's implementation. Breaking change in std.regex.replace with delegate, use Captures!string instead of RegexMatch!string as delegate parameter.
  • As typedef has been deprecated, overloads of std.conv.to which use typedef have now been deprecated.
  • std.array.insert has been deprecated. Please use std.array.insertInPlace instead.
  • The overload of std.array.replace which replaces in place has been deprecated. Please use std.array.replaceInPlace instead.
  • The toISOExtendedString and fromISOExtendedString functions on SysTime, Date, TimeOfDay, and DateTime in std.datetime have been deprecated. Please use toISOExtString and fromISOExtString instead.
  • std.file.getTimesPosix has been deprecated. Please use std.file.getTimes instead.
  • The overloads for isDir, isFile, and isSymlink in std.file which take a uint have been deprecated. Please use attrIsDir, attrIsFile, and attrIsSymlink instead.
  • Bugzilla 2550: implicit conversions don't apply to template value parameter specialization
  • Bugzilla 3467: Non-int integral template parameters not correctly propagated
  • Removed top const from dynamic array types and pointer types in IFTI.

Druntime Bugs Fixed

  • Bugzilla 6909: incorrect definition of the OVERLAPPED struct in core.sys.windows.windows ?

Library Bugs Fixed

  • Unlisted bug: std.conv: Fix to!float("-0")
  • Unlisted bug: std.file broken on OS X x86_64 due to wrong stat64 declaration.
  • Bugzilla 2936: std.regex.match() short string optimization
  • Bugzilla 4765: std.math.modf always returns 0
  • Bugzilla 5193: SList cannot have struct elements that have immutable members.
  • Bugzilla 5620: Implicit conversion of RegexMatch to bool.
  • Bugzilla 5712: [patch] std.regex.replace disallows w/dstring
  • Bugzilla 6204: emplace() for classes accepts larger chunk but fails in array assignment
  • Bugzilla 6887: Regression of getopt
  • Bugzilla 6888: std.getopt.getopt: one-letter hash option causes range violation
  • Bugzilla 6935: struct with @disable this cannot make range
  • Bugzilla 6953: std.concurrency needs more documentation
  • Bugzilla 6973: static assert(isOutputRange!(OutputRange!int, int)) is false
  • Bugzilla 6976: GetLastError called as property
  • Bugzilla 6977: getErrno called as property in std.stdio
  • Bugzilla 6979: hasUnsharedAliasing cannot accept plural parameters
  • Bugzilla 6990: std.string.splitlines deprecation doc missing a word
  • Bugzilla 7000: missing import of std.stdio in std.regex?
  • Bugzilla 7039: Posix 2.057 Makefile error breaking 64bit build
  • Bugzilla 7040: Phobos must use "version/else version" blocks for proper documentation generation.
  • Bugzilla 7045: AssertError in std.regex on line 1573
  • Bugzilla 7055: to!float("INF2") == 2

DMD Bugs Fixed

  • Bugzilla 2095: covariance w/o typechecks = bugs
  • Bugzilla 2532: '=' does not give a boolean result
  • Bugzilla 2778: alias this + IFTI doesn't work.
  • Bugzilla 2856: static opIndex does not compile for a templated struct/class
  • Bugzilla 3990: Deferencing a dynamic array as pointer
  • Bugzilla 4047: [CTFE] class/struct heap allocation
  • Bugzilla 4401: auto functions cannot be inner functions
  • Bugzilla 4511: Contravariance problem
  • Bugzilla 4583: PIC code not working: EBX register set incorrectly
  • Bugzilla 5311: Pure is broken when accessing globals / static data through instance reference
  • Bugzilla 5364: optimizer kills high dword of -1
  • Bugzilla 5416: null should have a type of its own
  • Bugzilla 5899: auto-return function cannot match 'null' with reference type.
  • Bugzilla 6056: Type lookup problem in string mixins
  • Bugzilla 6077: CTFE: Cannot append null array to null array.
  • Bugzilla 6330: Cannot disable assignment to a struct.
  • Bugzilla 6354: Optimizer bug on x86_64: Bitshift optimized out when foreach and scope(failure) are used
  • Bugzilla 6416: [CTFE] Declaration static struct is not yet implemented in CTFE
  • Bugzilla 6479: spurious alias this with struct and mixin template
  • Bugzilla 6522: [CTFE] Problem with opAssign call in foreach(ref)
  • Bugzilla 6603: [CTFE] Can't call through a manifest constant function pointer
  • Bugzilla 6736: Regression(2.054): ICE (cgcod.c 1672) with alias this and certain structs
  • Bugzilla 6763: Using TypeTuple with (const/in/ref etc.) changes it forever
  • Bugzilla 6792: [CTFE] ICE with pointer cast of indexed array
  • Bugzilla 6800: [CTFE] dangerous pointer casts should be rejected
  • Bugzilla 6805: Can't use a type from opDispatch template
  • Bugzilla 6816: [CTFE] nested function can't access this
  • Bugzilla 6817: [CTFE] Error on interpreting inlined IfStatement
  • Bugzilla 6832: Can't test objects wrapped with alias this
  • Bugzilla 6836: map + UFCS = fail
  • Bugzilla 6837: alias this + UFCS = fail
  • Bugzilla 6851: [CTFE] Cannot deref pointer passed by argument
  • Bugzilla 6859: Segfault when abstract method uses with contract.
  • Bugzilla 6864: Const conversion should precedence over the shared one
  • Bugzilla 6865: inout matching removes shared qualifier
  • Bugzilla 6866: ICE(mtype.c): alias this and inout matching
  • Bugzilla 6867: inout and nested foreach loops
  • Bugzilla 6868: IsExp + incorrect static array type = error
  • Bugzilla 6870: type qualifiers behave inconsistently in combination with typeof
  • Bugzilla 6872: Breaking type parsing of shared(inout(int)[])
  • Bugzilla 6877: [XMM] regression, clobbered float value
  • Bugzilla 6879: The difference of between template matching and IsExp
  • Bugzilla 6881: [XMM] ICE with painted float
  • Bugzilla 6885: [CTFE] wrong code with dynamically allocated 2D array
  • Bugzilla 6886: [CTFE] ICE(interpret.c) new array with initializer
  • Bugzilla 6901: wrong error "override cannot be applied to variable" in CTFE forward reference
  • Bugzilla 6902: Different "pure nothrow int()" types
  • Bugzilla 6910: __traits(hasMember, "") does not work, if template has alias param
  • Bugzilla 6912: const(T)[] can be implicitly cast to inout(const(T)[])
  • Bugzilla 6919: [CTFE] Cannot get effect to local variable through its pointer
  • Bugzilla 6922: [TDPL] superimposing of const and immutable does not work correctly
  • Bugzilla 6927: Better @property management by chained functions
  • Bugzilla 6928: alias this, immutable and common type fail in presence of fields with indirections
  • Bugzilla 6929: [ICE] typeMerge crashes in presence of ambiguous alias this conversions
  • Bugzilla 6941: .stringof displays redundant storage classes
  • Bugzilla 6972: [CTFE] ICE with ubyte/=uint
  • Bugzilla 6994: Using explicit 'this' in template constraint causes an error
  • Bugzilla 6997: 64bit optimizer bug
  • Bugzilla 7004: Iterating tuple with index which explicitly typed as size_t causes an error
  • Bugzilla 7026: 64 bit optimizer bug
  • Bugzilla 7027: Struct member trySemantic() regression in DMD Git master
  • Bugzilla 7028: Fails to save FPU regs when executing finally block
  • Bugzilla 7072: [2.057 Beta] Assertion failure: '0' on line 145 in file 'mtype.c'
  • Bugzilla 7093: aliased type sometimes isn't resolved
Version D 2.056 Oct 26, 2011

New/Changed Features

  • add -gs compiler switch
  • Bugzilla 3194: invariant should be checked at the beginning and end of protected functions
  • Bugzilla 5399: Return the result of a nonvoid function in a void function
  • Bugzilla 6752: Add separate option to control stack frame generation
  • std.exception: enforce/enforceEx now can use in @safe pure function.
  • Added optional KeepTerminator param to std.string.splitLines.
  • Added std.string.outdent.
  • std.utf: More @safe and pure.
  • std.windows.registry now use *W functions in order to deal properly with Unicode.

Druntime Bugs Fixed

  • Bugzilla 5967: Mangling of ArgClose for variadic function is swapped
  • Bugzilla 6493: Source code for the doc of core.time points to std.datetime.
  • Bugzilla 6466: core.demangle incorrect demangling of variables

Library Bugs Fixed

  • Bugzilla 5522: std.range.zip fails on arrays of Object.
  • Bugzilla 6009: std/container disabled on freebsd/64
  • Bugzilla 6160: std.conv.to: Ignore _ to match the rest of D
  • Bugzilla 6181: assert fails in datetime.d while runining Phobos unittest
  • Bugzilla 6258: std.conv.to!real("-") fetches the front of an empty array.
  • Bugzilla 6275: Const values in tuples
  • Bugzilla 6288: std.conv.to removes const/immutable when converting a class
  • Bugzilla 6609: std.conv.parse!Integer should consider sign when radix == 10
  • Bugzilla 6634: std.path.globMatch throws wrong assertion
  • Bugzilla 6640: More formatting consistency between string and range of char
  • Bugzilla 6761: Strange behavior of RedBlackTree causing a dangling pointer
  • Bugzilla 6819: BigInt ^^ fails for some big numbers (powers)

DMD Bugs Fixed

  • Bugzilla 546: Error message for accessing a deprecated variable is doubled
  • Bugzilla 1339: Invariant/const-ness is broken by built-in array properties sort and reverse
  • Bugzilla 1891: Array-concatenation of T* and T*[] produces corrupted result
  • Bugzilla 1993: Error calling vararg delegate with null
  • Bugzilla 2315: DMD Stack Overflow on unwanted ctfe recursion
  • Bugzilla 2553: Excess attribute propagation for interfaces
  • Bugzilla 2361: delete is allowed on invariant references.
  • Bugzilla 2737: Nonsensical Error Message on Unsafe .idup
  • Bugzilla 2740: Template Mixins do not work as advertised
  • Bugzilla 2953: tuple.length rejected as a tuple parameter in a static foreach
  • Bugzilla 3069: Array literals do not implicitly cast to void[]
  • Bugzilla 3133: Compiler does not check that static array casts are legal
  • Bugzilla 3180: Covariance of delegates/function pointers
  • Bugzilla 3550: array.dup violates const/invariant without a cast.
  • Bugzilla 3659: Too much exegesis on opEquals
  • Bugzilla 3748: inout does not work properly
  • Bugzilla 4022: [CTFE] AA get
  • Bugzilla 4197: ICE(glue.c): error in forward-referenced in/out contract
  • Bugzilla 4206: type accepted as enum initializer
  • Bugzilla 4237: Typedefs of the same name cause initializer conflict
  • Bugzilla 4269: Regression(2.031): invalid type accepted if evaluated while errors are gagged
  • Bugzilla 4284: empty string[] alias lacks .length in a template
  • Bugzilla 5453: ICE(statement.c): invalid switch statement forward referenced by CTFE
  • Bugzilla 5696: Templates typetuple iteration
  • Bugzilla 5703: std.intrinsic. and core.bitop.bsf, bsr and bswap should be CTFE-able
  • Bugzilla 5886: Template this parameter cannot be made implicit, when other parameters are explicitly given
  • Bugzilla 5932: Internal error: s2ir.c 339
  • Bugzilla 6062: segv in dmd/64 with assoc array literals
  • Bugzilla 6073: Cannot pass __traits(parent, ...) as a template parameter if it is a module
  • Bugzilla 6084: Impossible to instantiate local template with TypeTuple-foreach iterator variable.
  • Bugzilla 6087: typeof(this) doesn't work outside member function
  • Bugzilla 6139: Duplicate error message on compile-time out of bounds array index
  • Bugzilla 6289: Make slices of const/immutable arrays mutable (but keep the elements const/immutable)
  • Bugzilla 6296: ICE(glue.c): invalid template instantiated in is(typeof()).
  • Bugzilla 6352: Regression(2.054) Implicit pure/nothrow/@safe messes up delegate arrays
  • Bugzilla 6360: @property is doubled in di files when used with auto
  • Bugzilla 6404: Cannot check ref-ness of auto ref parameter in template constraint
  • Bugzilla 6488: DMD compiler bug
  • Bugzilla 6518: break inside a static foreach inside a switch
  • Bugzilla 6529: writeln(const array of enums) too
  • Bugzilla 6584: ICE on large version number/debug level
  • Bugzilla 6596: Error message with not extern(C) function
  • Bugzilla 6599: Segfault: invalid expression in initializer
  • Bugzilla 6630: Assigning null to class with nested alias this class is misinterpreted
  • Bugzilla 6656: static alias this broken in 2.055
  • Bugzilla 6661: Templates instantiated only through is(typeof()) shouldn't cause errors
  • Bugzilla 6665: Regression(2.055) ICE(cg87.c): static double inside closure
  • Bugzilla 6672: [CTFE] ICE on compile time std.algorithm.sort
  • Bugzilla 6674: Regression(2.055) mixin and __traits(allMembers) generates incorrect result
  • Bugzilla 6675: Regression(2.054) ICE(glue.c) template parameter deduction with errors gagged
  • Bugzilla 6682: Template function that has lazy parameter is not inferred as pure
  • Bugzilla 6690: Using lazy parameter should be inferred as @safe
  • Bugzilla 6691: static constructor inside template cannot initialize immutable template members
  • Bugzilla 6693: [CTFE] Cannot set value to nested AA
  • Bugzilla 6695: typeof(this) does not take into account const/immutable attributes inside member functions
  • Bugzilla 6698: Regression(2.053): segfault with naked asm in inner function
  • Bugzilla 6700: Regression(2.053) using $ inside a slice of a tuple
  • Bugzilla 6719: "Error: out of memory" in parsing
  • Bugzilla 6721: [CTFE] Cannot get pointer to start of char[]
  • Bugzilla 6727: [CTFE] ICE(interpret.c): assignment from string literal.dup.ptr
  • Bugzilla 6733: Regression(2.054) ICE(cod2.c) pure nothrow func with side-effect parameters
  • Bugzilla 6739: [CTFE] Cannot set a value to an outer AA of a nested AA
  • Bugzilla 6746: static this() inside struct skipped upon static method call
  • Bugzilla 6749: [CTFE] problem with array of structs
  • Bugzilla 6751: [CTFE] ref argument of AA doesn't work
  • Bugzilla 6753: Regression(2.055beta) "Reinterpret" cast of array to a tail const one doesn't work inside @trusted
  • Bugzilla 6759: missing initialization in foreach with alias this
  • Bugzilla 6765: [CTFE]: AA.length doesn't compile when AA is null
  • Bugzilla 6769: [CTFE] AA.keys doesn't compile when -inline is used
  • Bugzilla 6770: inout is allowed on fields
  • Bugzilla 6773: inout variable should not be modifiable
  • Bugzilla 6775: [CTFE] foreach over an AA fails to compile
  • Bugzilla 6782: inout-correct range is not iterable using foreach with type deduction inside non-inout function
  • Bugzilla 6813: Yet another "cannot get frame pointer" error
  • Bugzilla 6822: New ubuntu linking rules prevent dmd from linking programs on Ubuntu 11.10
  • Bugzilla 6825: Regression(2.055+): Address of templated method incorrectly taken
Version D 2.055 Sep 4, 2011

New/Changed Features

  • Added dman
  • Add support for Mac OS X 10.7 Lion
  • Add protection to json output
  • Add SSE4.1 and SSE4.2 assembly instructions
  • Bugzilla 4375: Require explicit braces when 'else' is ambiguous
  • std.algorithm.copy now specializes on arrays for 10-80x improved performance.
  • std.path has been rewritten from scratch and has a completely new API.
  • std.utf.toUTFz allows you to get a zero-terminated string of any character type and of any type of mutability.
  • Added symlink and readLink to std.file for Posix systems.
  • Values for GDC and LDC were added to std.compiler.Vendor.
  • Added functions to std.bitswap for generically handling swapping endianness.
  • Added std.parallelism.TaskPool.workerIndex.
  • Added buffer recycling overload of std.parallelism.asyncBuf
  • std.math.tgamma, lgamma, erf, and erfc are now deprecated. The equivalent functions in std.mathspecial should be used instead.
  • The names of the values of std.mmfile.Mode, std.system.Endian, std.traits.FunctionAttributes, std.traits.ParameterStorageClass, and std.traits.Variadic were changed to match Phobos' naming conventions.
  • std.range: Added indexed and chunks
  • std.string.translate has been updated to work with unicode. As a result, its signature has been changed. The old version and std.string.maketrans have been scheduled for deprecation.
  • std.string.tr has been updated so that it works with any string type.
  • std.conv.parse works for associative array and static array
  • std.format: Improvement of formatValue and unformatValue. They now works for associative array, consider element escaping, and treat range format spec more properly.
  • std.complex: added sin(), cos(), sqrt()
  • md5: 1.4X speedup

Druntime Bugs Fixed

  • Bugzilla 5967: Mangling of ArgClose for variadic function is swapped
  • Bugzilla 6493: Source code for the doc of core.time points to std.datetime.
  • Bugzilla 6466: core.demangle incorrect demangling of variables

Library Bugs Fixed

  • Unlisted bug: std.range.transversal should have length
  • Bugzilla 3890: Bad writeln of a nested struct
  • Bugzilla 4500: scoped moves class after calling the constructor
  • Bugzilla 4977: cannot use nothrow or pure with Rebindable
  • Bugzilla 5237: writefln doesn't respect Complex.toString
  • Bugzilla 5645: std.range.drop()
  • Bugzilla 5825: write is calling a deprecated function
  • Bugzilla 6040: std.cpuid and core.cpuid return different values for some methods
  • Bugzilla 6064: std.array.join is unnecssarily slow for strings
  • Bugzilla 6194: [GSoC] Destructor gets called on object before it is copied when calling writeln()
  • Bugzilla 6261: [2.054 beta regression] Regex cannot take a char[]
  • Bugzilla 6301: Cannot 'zip'/'retro'/'stride' etc. a range having 'ulong' length.
  • Bugzilla 6377: std.conv.to should check range when changing signedness
  • Bugzilla 6424: std.traits.hasElaborateAssign is limited
  • Bugzilla 6448: writef("%05d", BigInt) problem
  • Bugzilla 6514: CTFE dot product
  • Bugzilla 6587: std.parallelism's Task cannot handle immutable values
  • Bugzilla 6606: RefCounted doesn't work with unions due to use of format
  • Bugzilla 6608: Tuple field is not escaped

DMD Bugs Fixed

  • Bugzilla 1471: Linker error on template function. Error 42: Symbol Undefined ...
  • Bugzilla 1567: call to private super-constructor should not be allowed
  • Bugzilla 1684: offsetof does not work, adding cast is workaround
  • Bugzilla 1904: wrong protection lookup for private template functions
  • Bugzilla 2156: [] and null should be accepted where a compile-time string is required
  • Bugzilla 2234: __traits(allMembers) returns incorrect results for mixin and template alias members of an aggregate
  • Bugzilla 2245: Bug with overloaded, mixin template functions in classes
  • Bugzilla 2246: Regression(2.046, 1.061): Specialization of template to template containing int arguments fails
  • Bugzilla 2540: super can not be using in alias statement
  • Bugzilla 2634: Function literals are non-constant.
  • Bugzilla 2355: is() doesn't resolve aliases before template matching
  • Bugzilla 2579: Template function accepting a delegate with in argument doesn't compile
  • Bugzilla 2774: Functions-as-properties makes it impossible to get the .mangleof a function
  • Bugzilla 2777: alias this doesn't forward __dollar and slice op.
  • Bugzilla 2781: alias this doesn't work with foreach
  • Bugzilla 2787: Members found in an 'alias this' are not implicitly accessible in methods
  • Bugzilla 2941: Wrong code for inline asm because CPU type is set too late
  • Bugzilla 3268: can't compare pointer to functions when one is const
  • Bugzilla 3273: Regression(2.031): struct invariant + dtor fails to compile (no line number)
  • Bugzilla 3512: dchar iteration over string in CTFE fails
  • Bugzilla 3661: ^^ not supported in array operations.
  • Bugzilla 3797: Regression(2.038): Implicit conversion between incompatible function pointers
  • Bugzilla 4021: [CTFE] AA rehash
  • Bugzilla 4099: Inconsistent behaviour of ++/-- when mixing opUnary and 'alias this'.
  • Bugzilla 4444: Cannot index built-in array with expression tuple
  • Bugzilla 4460: Regression(2.036) ICE(e2ir.c) when compiling foreach over associative array literal
  • Bugzilla 4682: [CTFE] Run-time Vs Compile-time of int.min % -1
  • Bugzilla 4773: Rebindable should be castable to bool
  • Bugzilla 4837: ICE(constfold.c) CTFE with >>>=
  • Bugzilla 4984: Recursive template constraint results in dmd running out of memory
  • Bugzilla 5046: Wrong type of implicit 'this' in struct/class templates
  • Bugzilla 5081: Pure functions as initializers for immutable structures
  • Bugzilla 5188: alias this and compare expression generates wrong code
  • Bugzilla 5239: optimizer misreports an used before set error
  • Bugzilla 5373: Regression (2.051) CTFE and std.string.replace() causes "Bad binary function q{a == b}..
  • Bugzilla 5440: ICE(template.c): when struct AssociativeArray is missing from object.d
  • Bugzilla 5585: bad debug line number info for return statements with enumerator expressions
  • Bugzilla 5745: Missing error line number with lazy argument
  • Bugzilla 5750: Allow pure functions to have lazy arguments
  • Bugzilla 5777: Move semantics require full spec NRVO
  • Bugzilla 5785: Lexing or Parsing issue with UFCS
  • Bugzilla 5790: 'Error: variable result used before set' when -release -inline -O
  • Bugzilla 5799: Address-of operator fails on nested conditional operator expression
  • Bugzilla 5936: Regression(2.050): Segfault when forward-referencing pure auto-return member function with parameter.
  • Bugzilla 5953: Too many trailing commas are accepted
  • Bugzilla 6097: SSSE3 not working with MMX instructions
  • Bugzilla 6215: LLVM-compiled DMD segfaults due to mem.c alignment issues
  • Bugzilla 6220: Regression(2.053) static foreach over a string[] no longer produces directly usable strings
  • Bugzilla 6228: Regression(2.053) ICE(e2ir.c) on {auto x = (*ptr) ^^ y} with const integer types
  • Bugzilla 6230: Member functions can no longer be weakly pure
  • Bugzilla 6250: [CTFE] Crash when swapping two pointers to arrays.
  • Bugzilla 6265: Pure-inference failed when calling other pure functions
  • Bugzilla 6270: XMMREGS not preserved on indirect function call
  • Bugzilla 6276: [CTFE] Strange behavior of using ~= operator twice
  • Bugzilla 6280: [CTFE] Cannot put 'in' expression of AA in an 'if' condition
  • Bugzilla 6281: [CTFE] A null pointer '!is null' returns 'true'.
  • Bugzilla 6282: [CTFE] ICE when dereferencing a pointer to reference type from 'in' of an AA
  • Bugzilla 6283: [CTFE][Regression 2.054] Failed to assign to AA using a constness-changed array as key
  • Bugzilla 6284: [Regression 2.054] 'pure' does not work with 'with' statement
  • Bugzilla 6286: Regression(2.054): Static arrays can not be assigned from const(T)[N] to T[N]
  • Bugzilla 6293: [Regression 2.054] The expression x.y makes the function impure when the 'x' part is not just a variable
  • Bugzilla 6295: [Regression 2.054] Segfault in checkPurity() of template value parameter
  • Bugzilla 6306: Regression(2.054): [CTFE] Strange behavior of indirect recursive call in CTFE
  • Bugzilla 6308: Destruction of temporaries on exception causes unhandled access violation
  • Bugzilla 6316: Regression(2.054): Class downcast is rejected in @safe code
  • Bugzilla 6317: ICE on struct literal of nested struct
  • Bugzilla 6331: [CTFE] Cannot evaluate SliceExp on if condition
  • Bugzilla 6337: [CTFE] ICE when touching member variable of struct during CTFE
  • Bugzilla 6344: [CTFE] Assertion Failure in interpret.c when create an empty slice from null pointer
  • Bugzilla 6351: Regression(2.054) Segfault: Vararg delegate as template param
  • Bugzilla 6355: Template constructor cannot initialize non-mutable field
  • Bugzilla 6366: alias this doesn't work with foreach range.front
  • Bugzilla 6369: alias this doesn't work with initializer
  • Bugzilla 6374: [CTFE] Cannot subscript using pointer to array
  • Bugzilla 6375: [CTFE] Segfault when using std.array.appender with an initial array
  • Bugzilla 6386: [CTFE] ICE on pointer casting
  • Bugzilla 6389: Segfault(dsymbol.c): deprecated @disable
  • Bugzilla 6399: [CTFE] struct member array.length -= x doesn't work, while array[0..$-x] works
  • Bugzilla 6404: Cannot check ref-ness of auto ref parameter in template constraint
  • Bugzilla 6418: [CTFE] Cannot call a struct member function with name 'length'.
  • Bugzilla 6420: [CTFE] ICE on dereference-assigning to a pointer casted from a literal
  • Bugzilla 6429: Nested function error in reduce
  • Bugzilla 6433: Meta-Bug AA type propagation
  • Bugzilla 6434: opDispatch must be considered before alias this.
  • Bugzilla 6491: Fully qualified values in default arguments of non-template functions are generated with an extra 'module' keyword
  • Bugzilla 6499: [GSoC] Destructor not called on object returned by method.
  • Bugzilla 6505: Wrong code for expression involving 8 floats, only with -O
  • Bugzilla 6508: alias this doesn't work with AssignExp rhs
  • Bugzilla 6510: [CTFE] "internal error: illegal stack value" when compiled with -inline
  • Bugzilla 6511: [CTFE] Array op gives wrong result
  • Bugzilla 6512: [CTFE] new T[][] doesn't work
  • Bugzilla 6516: Regression(2.055 beta) [CTFE] ICE(constfold.c) involving new dchar[]
  • Bugzilla 6517: [CTFE] ptr++ doesn't work but ++ptr does
  • Bugzilla 6546: alias this + IdentityExpression doesn't work
  • Bugzilla 6556: ICE for ImportStatement in DebugStatement
  • Bugzilla 6558: [CTFE] UTF-decoding foreach gives wrong index (1-indexed)
  • Bugzilla 6561: alias this + undefined symbol should cause error
  • Bugzilla 6563: wrong code when using at least 8 XMM regs
  • Bugzilla 6577: 'Cannot initialize member' error line number
  • Bugzilla 6601: Regression(2.053): CTFE segfault taking address of function template
  • Bugzilla 6602: Invalid template instantiations leaked by is(typeof())/__traits(compiles, )/Type::trySemantic
Version D 2.054 Jul 10, 2011

New/Changed Features

  • Implement @safe
  • Implement @property
  • Automatic inference for @safe, pure, nothrow
  • Allow labelled break and continue in CTFE
  • Warn about switch case fallthrough
  • Pointers are now supported in CTFE
  • Heap-allocated structs are now supported in CTFE
  • Added SSSE3 instructions to inline assembler
  • Change from warning to deprecated: non-final switch statements must have a default statement
  • Change from warning to deprecated: function is hidden by function
  • Add warning about switch case fallthrough
  • Add warning about calling pure nothrow functions and ignoring the result
  • Allow associative arrays with key of type bool
  • Added inference for purity and safety
  • Change win32 dmd to not emit a map file unless asked for with -map
  • Added -property switch
  • Bugzilla 5823: @property call syntax restriction not implemented
  • Added core.sys.posix.netdb
  • For functions which have a version which takes a core.time.Duration and another version which takes an integral value, the version which takes an integral value is now scheduled for deprecation.
  • std.array.insertInPlace supports inserting of multiple ranges/elements in one go
  • Added std.array.uninitializedArray and std.array.minimallyInitializedArray
  • Various functions in std.string were renamed to match Phobos' naming conventions and be properly camelcased. The old names are still there but have been scheduled for deprecation.
  • Various functions in std.uni were renamed so that they don't have "Uni" in their name, since it was decided that it was not desirable to repeat a module's name in its functions' names. The old names are still there but have been scheduled for deprecation.
  • std.ctype has been scheduled for deprecation. std.ascii has been added to replace it.
  • Major performance improvements for std.algorithm.sort
  • std.string.atoi has been removed; replace it with std.conv.to!int
  • Switched to using posix.mak instead of various .mak files

Druntime Bugs Fixed

  • Bugzilla 4323: std.demangle incorrectly handles template floating point numbers
  • Bugzilla 5272: Postblit not called on copying due to array append
  • Bugzilla 5956: Undocumented mangling of struct value
  • Bugzilla 6135: Thread/GC interaction bug on OS X

Library Bugs Fixed

  • Bugzilla 2108: regexp.d: The greedy dotstar isn't so greedy
  • Bugzilla 3136: Incorrect and strange behavior of std.regexp.RegExp if using a pattern with optional prefix and suffix longer than 1 char
  • Bugzilla 3457: rdmd fails silently in a particular setup where the compiler is not the expected
  • Bugzilla 3479: writef/writefln: positional precision not working
  • Bugzilla 3564: Rdmd failing to link external C libraries
  • Bugzilla 3752: File.byLine fetches lines in a confusing manner
  • Bugzilla 4367: std.regex: Captures is not a random access range
  • Bugzilla 4574: std.regex: breaks with empy string regex
  • Bugzilla 4608: std.string.chomp documentation mismatch implementation
  • Bugzilla 5019: In std.regex, empty capture at end of string causes error
  • Bugzilla 5059: String assignment in foreach loop breaks immutability
  • Bugzilla 5458: scope for function parameters is not documented
  • Bugzilla 5511: std.regex optional capture with no-match cause error
  • Bugzilla 5598: rdmd does not fail on invalid filename
  • Bugzilla 5673: Add lookahead and forgetful matching support std.regex
  • Bugzilla 5705: Swapping identical struct with hasElaborateAssign causes "overlapping array copy" exception
  • Bugzilla 5836: std.typetuple.staticIndexOf's example code missing %s in call to writefln
  • Bugzilla 5857: std.regex (...){n,m} is bogus when (...) contains repetitions
  • Bugzilla 5869: std.thread needs to be removed
  • Bugzilla 6026: DLL example needs update due to missing core.dll_helper
  • Bugzilla 6076: regression, std.regex: "c.*|d" matches "mm"
  • Bugzilla 6101: Documentation for dead modules still distributed with DMD
  • Bugzilla 6113: singletons in std.datetime are not created early enough
  • Bugzilla 6193: Appender.clear() functionality or documentation

DMD Bugs Fixed

  • Bugzilla 693: 'this' can't be used as an alias parameter for a mixin
  • Bugzilla 1373: typeof(func).stringof fails when func has parameters.
  • Bugzilla 1411: ref Tuple should transform to Tuple of ref's
  • Bugzilla 1570: Wrong return for address operator
  • Bugzilla 2180: filename error with #line
  • Bugzilla 2521: Not possible to return immutable value by ref
  • Temp destructors now called if exception is thrown
  • Bugzilla 2625: Creating new struct with literal bypasses immutability of members if struct is in array
  • Bugzilla 3147: Incorrect value range propagation for addition
  • Bugzilla 3359: Cannot parse pure/const/immutable functions with inferred return type
  • Bugzilla 3445: partial fix
  • Bugzilla 3511: ref return property confused with property setter
  • Bugzilla 3632: modify float is float to do a bitwise compare
  • Bugzilla 3688: Can't have declaration with assignment to const/immutable inside if condition
  • Bugzilla 3722: A method without an in contract should always succeed, even if overridden
  • Bugzilla 3799: isStaticFunction trait evaluates to true for non-static nested functions
  • Bugzilla 4031: Should be able to access const value-type globals from pure functions
  • Bugzilla 4040: const/immutable on the right in auto return class methods
  • Bugzilla 4063: [CTFE] key not found in AA gives bad error message
  • Bugzilla 4065: [CTFE] AA "in" operator doesn't work
  • Bugzilla 4107: Duplicate documentation for member function templates
  • Bugzilla 4132: pointer arithmetic accepted in @safe functions
  • Bugzilla 4170: Missing line number on compile-time array index
  • Bugzilla 4258: "auto ref" doesn't work in one or more cases
  • Bugzilla 4448: [CTFE] labeled break doesn't work in CTFE
  • Bugzilla 4494: ICE(cod1.c) Array literal filled with results of void function
  • Bugzilla 4633: typeof({return 1;}()) declaration fails if inside main
  • Bugzilla 4661: Array Literal Incompatible Type Error Msg Should Include Line Number
  • Bugzilla 4706: Overloading auto return w/ non-auto return = strange error msg
  • Bugzilla 4745: Non-uniform handling of commas in static initialization of structs
  • Bugzilla 4885: Uninitialize Pointers Allowed in @safe code
  • Bugzilla 4910: [CTFE] Cannot evaluate a function that has failed at once
  • Bugzilla 4963: ICE(type.c:320) for struct append where T.sizeof < 3
  • Bugzilla 4969: nothrow check can't handle multiple catches
  • Bugzilla 5088: Cannot cast const(int) to long in @safe function
  • Bugzilla 5258: [CTFE] Stack overflow with struct by ref
  • Bugzilla 5284: Array ops punch through const system
  • Bugzilla 5327: Creating new struct with literal bypasses immutability of members of members of the struct
  • Bugzilla 5396: [CTFE] Invalid code with nested functions in CTFE
  • Bugzilla 5415: @Safe functions not working
  • Bugzilla 5497: -- now produces error message instead of wrong code
  • Bugzilla 5551: opUnary-opBinary conflict
  • Bugzilla 5574: Struct destructor freaks out when an array of struct with single element is instantiated inside a class
  • Bugzilla 5615: [CTFE] std.string.indexOf broken at compile time
  • Bugzilla 5633: [CTFE] ICE(constfold.c): is expression with struct, struct pointer, array literal...
  • Bugzilla 5657: Temporary object destruction
  • Bugzilla 5659: Conditional operator, array literal, and std.traits.CommonType return a wrong common type
  • Bugzilla 5676: [CTFE] segfault using tuple containing struct that has opAssign
  • Bugzilla 5682: [CTFE] Silently wrong result possibly related to operator overloading and expression order
  • Bugzilla 5693: Segfault with address of template struct opCall
  • Bugzilla 5708: [CTFE] Incorrect string constant folding with -inline
  • Bugzilla 5771: Template constructor and auto ref do not work
  • Bugzilla 5819: DMD doesn't error/warn about illegal asm for 64bit mode
  • Bugzilla 5845: Regression(2.041) [CTFE] "stack overflow" with recursive ref argument
  • Bugzilla 5856: overloading on const doesn't work for operator overload
  • Bugzilla 5859: Declaration inside if condition doesn't call destructor
  • Bugzilla 5861: Wrong filename in error message when an invalid delegate in a template parameter is typeof()-ed
  • Bugzilla 5885: wrong codegen for OPu32_d
  • Bugzilla 5897: unrelated struct type casting should ignite construction
  • Bugzilla 5936: Invalid code with nested functions in CTFE
  • Bugzilla 5946: failing lookup 'this' from function in template
  • Bugzilla 5954: [CTFE] enum structs with ctor
  • Bugzilla 5959: Return by reference with nested function should be allowed
  • Bugzilla 5962: Template function declaration with prefixed storage class and auto occurs conflict
  • Bugzilla 5963: iasm does not accept 64bit integer literal
  • Bugzilla 6001: [CTFE] ICE(interpret.c) mutating ref array
  • Bugzilla 6015: [CTFE] Strange behavior of assignment appears in a situation
  • Bugzilla 6049: [CTFE] Array literals of structs with invariant() are wrong
  • Bugzilla 6052: [CTFE] Struct elements in an array are treated like reference type
  • Bugzilla 6053: [CTFE] Two ICEs involving pointers (dereference and assign; pointer variable on stack)
  • Bugzilla 6054: [CTFE] ICE when returning a returned compile-time associative array containing a key of an idup-ed array literal
  • Bugzilla 6059: Incompatible types in array literal shows __error and error
  • Bugzilla 6072: [CTFE] Regression(git master): Cannot declare variable inside an 'if' condition
  • Bugzilla 6075: Cannot set value to associative array from a weakly-pure function when the value type has a (pure) opAssign
  • Bugzilla 6077: [CTFE] Cannot append null array to null array.
  • Bugzilla 6078: [CTFE] ICE on foreach over array struct member which is null
  • Bugzilla 6079: [CTFE] Array index out of bound detection is off-by-one
  • Bugzilla 6090: DDoc parenthesis escape issues.
  • Bugzilla 6100: [CTFE] Regression: struct return values wrong if used in array initializer
  • Bugzilla 6109: 'nothrow' does not check slice indices
  • Bugzilla 6111: Escaping reference to local variable not detected
  • Bugzilla 6119: Assertion failure: '0' on line 1118 in file 'glue.c'
  • Bugzilla 6120: [CTFE] ICE on calling constructor of template struct with -inline in function/delegate literal.
  • Bugzilla 6123: [CTFE] Cannot call a template member method inside delegate/function literal with -inline.
  • Bugzilla 6137: [CTFE] Foreach on semantically wrong initialized array crashes the compiler
  • Bugzilla 6145: Meaningless second error message for complex size of static array
  • Bugzilla 6150: runnable/testsocket.d
  • Bugzilla 6158: winsamp and dhry samples need an update
  • Bugzilla 6161: iasm opcode family Jcc use absolute address instead of relative for functions
  • Bugzilla 6164: [CTFE] Local arrays in a recursive local function behave funny
  • Bugzilla 6198: [GSoC] ICE(e2ir.c) With circular import
  • Bugzilla 6229: %= and /= no longer work on char type
  • Bugzilla 6230: Member functions can no longer be weakly pure
  • Bugzilla 6234: 64-bit array append generates inline code to copy new data, but does not call postblit
  • Bugzilla 6241: test sdtor.d on osx not catching
  • Bugzilla 6242: Disallow inoperant "in" contracts
  • Bugzilla 6264: ICE on testing opSlice in static if
  • Bugzilla 6267: Can't increment alias this'd struct from ref return
  • Bugzilla 6279: Regression(2.054 beta): array-vararg with pointer type not working in safe code
Version D 2.053 May 12, 2011

New/Changed Features

  • Added 64 bit tools to Linux
  • Added FreeBSD support
  • Renamed linux/bin to linux/bin32, added linux/bin64
  • osx/lib32 renamed back to osx/lib
  • Added some gc benchmark apps
  • Move std.intrinsic to core.intrinsic
  • Implemented exception chaining, as described in TDPL for Posix.
  • Added parent to __traits for QtD support
  • Allow impure code inside debug conditionals
  • Added cmpxchg16b, 64 bit bswap and movq instructions to internal assembler
  • Added bindings for libcurl: etc.c.curl
  • Added std.net.isemail
  • Added std.parallelism
  • Added support for positional parameter intervals, e.g. %1:3$s prints the first three parameters using the 's' format specifier
  • Added findSplit, findSplitBefore, findSplitAfter to std.algorithm; improved walkLength
  • Improved online documentation for std.algorithm
  • Added roundRobin, takeOne, and takeNone to std.range; improved stride
  • Added unsigned to std.traits
  • Removed std.iterator. Use either std.range.ElementType or std.range.ElementEncodingType depending on what you're trying to do.
  • Bugzilla 2656: Remove octal literals
  • Bugzilla 4097: Error: can only declare type aliases within static if conditionals
  • Bugzilla 4360: Allow intrinsics in core.bitop to operate as intrinsics
  • Bugzilla 4833: dmd -od doesn't make it to optlink's command line for map files

Druntime Bugs Fixed

  • Bugzilla 5612: core.cpuid not implemented on 64
  • Bugzilla 1001: print stack trace (in debug mode) when program die
  • Bugzilla 5847: Threads started by core.thread should have same floating point state as main thread

Library Bugs Fixed

  • Bugzilla 4644: assertExceptionThrown to assert that a particular exception was thrown
  • Bugzilla 4944: Missing tzname even though we have tzset
  • Bugzilla 5451: Three ideas for RedBlackTree
  • Bugzilla 5474: unaryFun byRef is borked for custom parameter name
  • Bugzilla 5485: TLS sections handled incorrectly in FreeBSD
  • Bugzilla 5616: std.datetime: not cross-platform
  • Bugzilla 5654: BigInt returns ZERO with strings of single digit number with leading zeros
  • Bugzilla 5661: std.algorithm.move does not work on elaborate struct
  • Bugzilla 5731: std.datetime.SysTime prints UTC offsets backwards
  • Bugzilla 5761: std.datetime: Date.this(int day) conversion fails for Dec 30 of leap years
  • Bugzilla 5780: [patch] std.traits.hasIndirections incorrectly handles static arrays
  • Bugzilla 5781: std.datetime: On Windows, times off by one hour in some years due to DST rule changes
  • Bugzilla 5794: std.datetime StopWatch (and perhaps benchmark) examples need a small fix
  • Bugzilla 5928: Bigint modulo problem -- critical wrong-code bug

DMD Bugs Fixed

  • Note: Although temporaries are destroyed now, they are not destroyed when exceptions are thrown. This is scheduled to be fixed.
  • Bugzilla 2436: Unexpected OPTLINK termination EIP = 00425303 with /co
  • Bugzilla 3372: optlink silently mistreats object files with more than 16384 symbols
  • Bugzilla 4275: Unexpected optlink termination when 'export' attribute is missing
  • Bugzilla 4808: UNEXPECTED OPTLINK TERMINATION AT EIP=0042787B
  • Bugzilla 5670: Optlink 8.00.11 crash
  • Bugzilla 937: C-style variadic functions broken
  • Bugzilla 1330: Array slicing does not work the same way in CTFE as at runtime
  • Bugzilla 1336: Inconsistent __traits usage
  • Bugzilla 1389: Can't use mixin expressions when start of a statement.
  • Bugzilla 1880: templates instantiated with non-constants should fail sooner
  • Bugzilla 2257: Template value parameters behave like alias parameters
  • Bugzilla 2414: enum is dynamically evaluated, yum
  • Bugzilla 2526: non-const initializer to constant accepted inside template
  • Bugzilla 2706: invalid template instantiation (and declaration?) is not rejected
  • Bugzilla 2733: Unclear semantics of template value parameters
  • Bugzilla 2841: char[] incorrectly accepted as a template value argument in D2
  • Bugzilla 2850: bad codegen for struct static initializers
  • Bugzilla 2990: TypeInfo.init() returns invalid array
  • Bugzilla 3086: TypeInfo opEquals returns incorrect results
  • Bugzilla 3214: Incorrect DWARF line number debugging information on Linux
  • Bugzilla 3271: Struct initializers silently fail
  • Bugzilla 3516: Destructor not called on temporaries
  • Bugzilla 3792: Regression(1.053) "non-constant expression" for a template inside a struct using a struct initializer
  • Bugzilla 3779: ["123"][0][$-1] causes __dollar unresolved in compile-time
  • Bugzilla 3801: CTFE: this.arr[i] cannot be evaluated at compile time for structs
  • Bugzilla 3835: ref foreach does not work in CTFE
  • Bugzilla 4033: Error: base class is forward referenced
  • Bugzilla 4050: [CTFE] array struct member slice update
  • Bugzilla 4051: [CTFE] array struct member item update
  • Bugzilla 4097: Error: can only declare type aliases within static if conditionals
  • Bugzilla 4140: Error: non-constant expression "hello"[1u..__dollar]
  • Bugzilla 4298: Constant array translated to unnecessary array literal creation
  • Bugzilla 4322: "void initializer has no value" on struct/union members initialized to "void"
  • Bugzilla 4329: Do not show error messages that refer to __error
  • Bugzilla 4360: Allow intrinsics in core.bitop to operate as intrinsics
  • Bugzilla 4437: copy construction bug with "return this;"
  • Bugzilla 4499: calls to @disabled postblit are emitted
  • Bugzilla 4543: Regression(1.054, 2.038) typedef causes circular definition and segfault
  • Bugzilla 4750: fail_compilation/fail225.d causes dmd to segv
  • Bugzilla 4815: CodeView: Global and Static symbols should have unmangled names
  • Bugzilla 4817: CodeView: Enum members should have simple names
  • Bugzilla 4833: dmd -od doesn't make it to optlink's command line for map files
  • Bugzilla 4917: Symbol conflict error message refers to aliased symbol instead of the alias
  • Bugzilla 5147: [CTFE] Return fixed-size matrix
  • Bugzilla 5268: Outdated windows GUI sample in Samples folder
  • Bugzilla 5362: checking $ in bracket is broken
  • Bugzilla 5482: Crash with align(0)
  • Bugzilla 5485: TLS sections handled incorrectly
  • Bugzilla 5524: [CTFE] Trouble with typesafe variadic function
  • Bugzilla 5647: [64-bit] Valgrind complains about illegal instruction
  • Bugzilla 5649: std.conv.parse faulty for floating point with -O -m32
  • Bugzilla 5657: Temporary object destruction
  • Bugzilla 5664: Cannot compile static synchronized member function.
  • Bugzilla 5694: va_arg doesn't work with idouble and ifloat
  • Bugzilla 5671: CTFE string concat problem
  • Bugzilla 5672: ICE(cod2.c): incorrect optimization of (long &1) == 1
  • Bugzilla 5678: new enum struct re-allocated at compile time
  • Bugzilla 5694: va_arg doesn't work with idouble and ifloat
  • Bugzilla 5706: Incorrect opcode prefix generated for x86_64 inline assembly
  • Bugzilla 5708: Incorrect string constant folding with -inline
  • Bugzilla 5717: 1.067 regression: appending Unicode char to string broken
  • Bugzilla 5722: Regression(2.052): Appending code-unit from multi-unit code-point at compile-time gives wrong result
  • Bugzilla 5735: non-scalar types implicitly converted to boolean
  • Bugzilla 5740: Unable to use this pointer in inline assembly
  • Bugzilla 5741: Add the SYSCALL and SYSRET opcodes to the inline assembler
  • Bugzilla 5798: Weakly pure function calls skipped inside a comma expression
  • Bugzilla 5812: Added constant fold optimisations for ^^ expressions
  • Bugzilla 5840: Cannot assign to an array member of struct in CTFE
  • Bugzilla 5852: CTFE: wrong code for string[] ~= const(string)
  • Bugzilla 5858: Import doesn't accept const string as argument
  • Bugzilla 5865: __dollar cannot be read at compile time
  • Bugzilla 5890: ICE and wrong scope problem for 2nd argument in static assert with DMD on git master
  • Bugzilla 5916: DMD: bad message for incorrect operands error
  • Bugzilla 5938: ICE ztc\symbol.c 1043
  • Bugzilla 5940: Cannot create arrays of std.algorithm.map
  • Bugzilla 5965: [2.053 beta] map rejects a predicate with anon-func and nested func
  • Bugzilla 5966: [2.053 beta][CTFE] Stack overflow on trivial func
  • Bugzilla 5972: CTFE: Can't assign to elements of arrays of slices
  • Bugzilla 5975: [2.053 beta][CTFE] ICE: 'global.errors' on line 1416 in file 'constfold.c'
  • Bugzilla 5976: "variable used before set" with foreach with ref + scope(failure) + structure method + -O -inline
  • Bugzilla 5982: [2.053 beta] std.iterator gone, but no mention of the change
  • Bugzilla 5987: mydll sample doesn't compile
  • Clarify tuple index out of bounds error message
  • Add 64 version of xchg and jmp to inline assembler. Fixed 64 bit LEA
  • CTFE: Generate error messages for accessing null arrays
  • Fix optimizer bug with to!float("123e2")
  • Fix spelling of cmpxchgb8
Version D 2.052 Feb 17, 2011

New/Changed Features

  • 64 bit support for Linux
  • Implemented exception chaining, as described in TDPL. Currently Windows-only.
  • std.random: Added Xorshift random generator
  • Support HTML5 entities
  • Added std.datetime for handling dates and times. std.date and std.gregorian are now scheduled for deprecation. Any functions in other modules of Phobos which used std.date.d_time have been changed to use std.datetime.SysTime or are scheduled for deprecation with new functions with the same functionality added which use SysTime (done in cases where switching existing functions to use SysTime would have broken code). New code should use std.datetime instead of std.date.
  • Various functions in std.file were renamed to match Phobos' naming conventions (e.g. isFile instead of isfile). The old names are aliased and scheduled for deprecation.

Bugs Fixed

  • Bugzilla 190: Cannot forward reference typedef/alias in default value for function parameter
  • Bugzilla 1513: try/catch/finally misbehavior on windows
  • Bugzilla 1899: AA of fixed-length arrays fails to initialize
  • Bugzilla 1914: Array initialisation from const array yields memory trample
  • Bugzilla 2581: DDoc doesn't work for functions with auto return type.
  • Bugzilla 2810: Bogus forward reference error with auto function
  • Bugzilla 2874: phobos docs issues
  • Bugzilla 3198: wrong initializer for structs arrays
  • Bugzilla 3334: std.demangle doesn't parse ref, pure, nothrow
  • Bugzilla 3681: ICE(go.c): when function takes too long to optimize, only with -O.
  • Bugzilla 3848: functions in std.file don't take symbolic links into account
  • Bugzilla 4013: Inconsistent codeview debug info for classes derived from IUnknown
  • Bugzilla 4069: Issue 4069 - std.xml.Document.pretty saves empty elements with spaces and line breaks
  • Bugzilla 4245: Declaring conflicting symbols in single function scope allowed
  • Bugzilla 4307: spawn()'ed thread doesn't terminate
  • Bugzilla 4328: templated unittests fail to link when instantiated from other file if compiler order isn't correct
  • Bugzilla 4379: ICE(blockopt.c): foreach over huge tuple, only with -O
  • Bugzilla 4389: ICE(constfold.c, expression.c), or wrong code: string~=dchar in CTFE
  • Bugzilla 4486: CodeView debug info should contain absolute path names
  • Bugzilla 4598: std.xml check is too restrictive
  • Bugzilla 4601: Spawned threads frequently don't terminate or let other threads ever run if you spawn more than one thread
  • Bugzilla 4732: __traits(identifier) performs constant folding on symbols
  • Bugzilla 4753: fail_compilation/fail116.d sends dmd into a loop, exhausting memory
  • Bugzilla 4807: Examples for std.array insert and replace
  • Bugzilla 4852: core.demangle cannot demangle functions with class/struct return types
  • Bugzilla 4878: Ddoc: Default arguments can break Ddoc output
  • Bugzilla 4913: Implicit opCast!bool in if statement doesn't work with declarator
  • Bugzilla 4973: map file with spaces in file name passed without quotes to linker
  • Bugzilla 5025: ICE(cast.c) shared struct literal
  • Bugzilla 5090: ICE(todt.c) struct literal initializing zero length array
  • Bugzilla 5105: Member function template cannot be synchronized
  • Bugzilla 5197: Ddoc: access-attributed auto template function crashes dmd
  • Bugzilla 5198: Appender much slower when appending ranges of elements than individual elements
  • Bugzilla 5209: posix/sys/select.d: FD_ISSET function should return bool
  • Bugzilla 5221: entity.c: Merge Walter's list with Thomas'
  • Bugzilla 5242: self referencing template constraint crashes compiler
  • Bugzilla 5244: PATCH: fix use of uninitialised variable in toObj.c
  • Bugzilla 5246: PATCH(s): fix a couple more uninitialised variables
  • Bugzilla 5248: CTFE Segfault when calling a function on an enum struct
  • Bugzilla 5271: Not constant RAND_MAX
  • Bugzilla 5320: gcstub/gc.d: SEGV because of missing returns
  • Bugzilla 5349: ICE(toir.c): nested class in static member function
  • Bugzilla 5365: Regression (2.051) implicit conversions via alias this are broken
  • Bugzilla 5381: Regression (2.051) switch fails for wstring and dstring
  • Bugzilla 5382: [regression 2.051] DLL multi-threading broken
  • Bugzilla 5391: Crash with recursive alias declaration
  • Bugzilla 5400: Add const to FD_ISSET
  • Bugzilla 5439: 64bit struct alignment inconsistent with C ABI
  • Bugzilla 5447: Should be illegal to throw a non-Throwable
  • Bugzilla 5455: ICE(cgcod.c): Optimization (register allocation?) regression in DMD 1.065
  • Bugzilla 5486: Missing define for running dmd as 64 bit
  • Bugzilla 5488: Spawned threads hang in a way that suggests allocation or gc issue
  • Bugzilla 5504: Regression(2.051): Template member functions of a shared class don't compile
  • Bugzilla 5534: [64-bit] Inexplicable segfault in small code snippet, -O -release -m64 only
  • Bugzilla 5536: Array append with dollar op on 64-bit
  • Bugzilla 5545: [64-bit] DMD fails to postincrement ubytes.
  • Bugzilla 5549: [64-bit] Internal error: backend/cgcod.c 1845
  • Bugzilla 5552: std.datetime.d DosFileTimeToSysTime has a bug
  • Bugzilla 5556: [64-bit] Wrong Implicit Conversion to Double
  • Bugzilla 5557: [64-Bit] FP (alignment?) issues with Rvalues
  • Bugzilla 5564: [64-bit] loading of wrong constant byte value
  • Bugzilla 5565: [64-bit] Wrong Floating Point Results, Related to Mixing With size_t
  • Bugzilla 5566: [64-bit] More erratic FP results with size_t
  • Bugzilla 5579: Segfault on first call to GC after starting new thread
  • Bugzilla 5580: [64-bit] String switch statements broken in 64-bit mode
  • Bugzilla 5581: [64-bit] Wrong code with bitwise operations on bools
  • Bugzilla 5592: Previous definition different: __arrayExpSliceMulSliceAddass_d
  • Bugzilla 5595: Compiler crash on heavy std.algorithm use
Version D 2.051 Dec 21, 2010

New/Changed Features

  • Added std.mathspecial, containing mathematical Special Functions
  • std.base64: Replaced. Boost License, Performance improvement, Range support. Function signature changed from 'encode' to 'Base64.encode'
  • std.math: D implementation of pow. Almost all std.math functions are now @safe pure nothrow. tgamma, lgamma, erf, erfc have been moved to std.mathspecial
  • std.exception: Added pure and nothrow to assumeUnique
  • std.utf: Removed UtfError class and toUTF* shortcut functions for validation. Added pure, nothrow, @safe and @trusted attributes. count function supports dchar
  • Both druntime and phobos now build successfully with dmd -m64. Still somewhat behind dmd1, very little executes correctly still.

Bugs Fixed

  • Bugzilla 603: Undocumented behaviour: case and default create a scope
  • Bugzilla 632: Typedef/enum promotions spec ambiguous - ultimate base type or lowest common denominator?
  • Bugzilla 679: Spec needs allowances for copying garbage collection
  • Bugzilla 690: ABI not fully documented
  • Bugzilla 1351: Discrepancies in the language specification
  • Bugzilla 1466: Spec claims maximal munch technique always works: not for "1..3"
  • Bugzilla 2080: ICE(mangle.c) alias corrupts type inference of static variables
  • Bugzilla 2206: unnamed template mixin of class inside function or class has incorrect classinfo and mangleof
  • Bugzilla 2385: spec says all structs are returned via hidden pointer on linux, but it uses registers
  • Bugzilla 2392: Parsing ambiguity between function pointer declaration and function call
  • Bugzilla 2406: Declarator2 definition error
  • Bugzilla 2556: Property classinfo needs better documentation (RTTI, typeof, typeid, runtime type information)
  • Bugzilla 2616: Undocumented behaviour: part-explicit, part-implicit instantiations of function templates are accepted
  • Bugzilla 2651: class body declaration grammar incorrect
  • Bugzilla 2652: DeclDef grammar is wrong
  • Bugzilla 2734: Ambiguity in tokenizing: _._ as a float literal
  • Bugzilla 2751: const/invariant/immutable static arrays: const(T)[N] and const(T[N]) are the same, but DMD treats them as different
  • Bugzilla 2954: [tdpl] Appalling bug in associative arrays (D2 only)
  • Bugzilla 2994: Incomplete "Predefined Versions" documentation
  • Bugzilla 3020: No description is given why function may not be nothrow
  • Bugzilla 3112: Specification on what operations call the GC is missing
  • Bugzilla 3276: Recursion broken by alias template parameter
  • Bugzilla 3554: Ddoc generates invalid output for documentation comments with non paired parantheses
  • Bugzilla 3864: Dyn array allocations can be allowed in nothrow functions
  • Bugzilla 4059: Incorrect C++ name mangling
  • Bugzilla 4217: Function overloads are not distinguished when instantiating templates
  • Bugzilla 4254: ICE(mtype.c): function with const inout parameter
  • Bugzilla 4297: Nothrow functions cannot use constant dynamic array
  • Bugzilla 4384: Cyclic dependency check for modules is broken
  • Bugzilla 4434: ICE(mtype.c, 887) alias with const, shared, or immutable
  • Bugzilla 4445: roundTo!ubyte(255.0) throws
  • Bugzilla 4529: Segfault(typinf.c) involving typeid(typeof(functionName))
  • Bugzilla 4638: Regression: new writeln does not recognize "wstring toString"
  • Bugzilla 4728: Segfault(toctype.c) by protected/private constructor in an other module
  • Bugzilla 4781: Segfault(mtype.c) with forward referenced typeof and .init
  • Bugzilla 4864: ICE(statement.c) Crash on invalid 'if statement' body inside mixin
  • Bugzilla 4901: std.algorithm.sort does not compile for interfaces.
  • Bugzilla 4915: auto return type escapes function purity
  • Bugzilla 5020: Forward implicit bool conversions to alias this
  • Bugzilla 5053: Better error message for cyclic dependencies.
  • Bugzilla 5054: Splitter example doesn't work
  • Bugzilla 5094: No implicit conversion with "alias property this"
  • Bugzilla 5107: Const-shared classes/structs not typed as shared
  • Bugzilla 5110: Excess attribute propagation of structs and classes
  • Bugzilla 5117: [CTFE] Member function call with rather complex this: side effects ignored
  • Bugzilla 5120: ICE(mtype.c) void associative arrays
  • Bugzilla 5131: Segfault(expression.c) opAssign and associative arrays (AA) are broken for types != this
  • Bugzilla 5133: dmd fails to build rdmd (problem with startsWith)
  • Bugzilla 5145: Regression(2.050, 1.065) override error with forward ref of superclass
  • Bugzilla 5148: Incorrect C++ mangling of multiple const char* parameters
  • Bugzilla 5154: Class Range does not work in writeln
  • Bugzilla 5159: Segfault(interpret.c): calling a static function pointer variable in CTFE
  • Bugzilla 5163: meaningless error message with front() applied to void[].
  • Bugzilla 5164: Error without line number using "is (T...)"
  • Bugzilla 5180: ICE(arrayop.c) in-place array operation on incompatible types
  • Bugzilla 5182: ICE(expression.c): calling unittest from a function
  • Bugzilla 5191: Combination of pure and nothrow result in a function that does nothing
  • Bugzilla 5194: ddoc does not show modifiers on constructors such as pure or nothrow
  • Bugzilla 5195: Forward references ignore const
  • Bugzilla 5214: Compiler crash with array of empty {}
  • Bugzilla 5218: Can't implicitly convert from "abc"w to wchar[3]
  • Bugzilla 5220: Make std.conv.ConvError an Exception instead of an Error; deprecated ConvError and ConvOverflowError with ConvException and ConvOverflowException. Note that any code depending on the fact that these exceptions were Error gets broken.
  • Bugzilla 5230: Regression(2.041, 1.057) ICE(tocsym.c) overriding a method that has an out contract
  • Bugzilla 5238: PATCH: fix return of uninitialised var in interpret.c
  • Bugzilla 5247: std.utf.stride() should not return 0xFF
  • Bugzilla 5275: x86_64 related hidden function parameter mishandled
  • Bugzilla 5293: std.math: Error: shift by -48 is outside the range 0..32
  • Bugzilla 5294: -O optimization breaks for loop
  • Bugzilla 5321: std.math: assumes X86 or X86_64 on FPU control word code
  • Bugzilla 5322: std.math: version(Sparc) should be SPARC
  • Bugzilla 5330: Druntime/Phobos: remove special treatment for GDC
  • Bugzilla 5331: mach format problem
  • Bugzilla 5340: isOutputRange!(Appender!string, int) must be false
  • Bugzilla 5353: clear function is calling the destructor twice
Version D 2.050 Oct 29, 2010

New/Changed Features

  • added talign() and argTypes() to TypeInfo
  • Upgrade zlib support to zlib 1.2.5
  • std.stdio: Added ByChunk. This struct is a InputRange like ByLine. File.byChunk returns ByChunk
  • std.traits: Most higher-order ranges now work with const/immutable arrays and other ranges with a natural tail const, and ranges w/ const/immutable elements.
  • Bugzilla 4888: Heavy reliance on Bug 3534 in Phobos range usage
  • Bugzilla 4987: C function pointer syntax needs to be deprecated
  • std.typecons: Several improvements to the Tuple struct template:
    • Tuple members are now accessible with the syntax a[0], a[1] etc.
    • Eliminated an internal union. See Bugzilla 4421 and Bugzilla 4846.
    • Worked around Bugzilla 4424. Got opAssign back.
    • Made Tuple.slice!(from, to) to preserve field names if any.
    • Added isTuple!(T) template.
  • std.algorithm: changed filter() such that filter is curryable
  • std.algorithm: Added function balancedParens
  • std.typecons: Deprecated defineEnum
  • Added relaxed purity checking rules.

Bugs Fixed

  • Unlisted bug: std.exception.pointsTo() calls postblit on subobjects.
  • Unlisted bug: std.typetuple.staticMap!() doesn't work with empty/single tuples.
  • Unlisted bug: std.traits: Interfaces should have indirections, aliasing, etc.
  • Unlisted bug: std.socket: Race condition - gethostbyname and gethostbyaddr on Linux return static data. The call was synchronized, but using the data wasn't
  • Unlisted bug: signed long comparisons under OS X
  • Bugzilla 941: std.regexp fails to match when grouping certain sub-expressions
  • Bugzilla 1482: std.file docs are insufficient
  • Bugzilla 1635: DirEntry.isfile() and DirEntry.isdir() broken
  • Bugzilla 1733: parse() function does not handle all build-in types
  • Bugzilla 2073: Variant.coerce!() fails
  • Bugzilla 2142: getopt() incorrectly processes bundled command-line options
  • Bugzilla 2310: Inconsistent formatting of arrays in std.stdio.write() and std.conv.to!(string)()
  • Bugzilla 2424: std.functional binaryRevertArgs : "revert" should be "reverse"
  • Bugzilla 2451: Adding structs that use opAssign or postblit to an AA is broken
  • Bugzilla 2655: Allow alternation patterns in std.path.fnmatch
  • Bugzilla 2669: Variant does not have opApply or another iteration mechanism
  • Bugzilla 2718: Inconsistent string parameters in Phobos functions
  • Bugzilla 2838: std.file.rmdirRecurse fails
  • Bugzilla 2930: Problems in std.range documentation
  • Bugzilla 2943: Struct copying in presence of alias member this only copies alias this member
  • Bugzilla 2965: std.date: timezone not initialized
  • Bugzilla 3157: [patch] Pipes should be closed with pclose
  • Bugzilla 3318: [PATCH]Rebindable.get is not accessible
  • Bugzilla 3570: mkdirRecurse throws exception on trailing empty directory.
  • Bugzilla 3602: ICE(tocsym.c) compiling a class, if its super class has preconditions
  • Bugzilla 3665: Regression(1.051, 2.036) Assignment with array slicing does not work
  • Bugzilla 4344: Sockets with multiple threads report missing/failed WSAStartup
  • Bugzilla 4398: dmd always uses Windows name mangling for _d_throw
  • Bugzilla 4439: The declaration of the in6addr_* in druntime is wrong.
  • Bugzilla 4465: ICE(symbol.c): immutable type inference with ^^2
  • Bugzilla 4524: Regression(2.026) Bus error with nested struct
  • Bugzilla 4623: Non-integer type allowed as static array size
  • Bugzilla 4634: typo in levenshteinDistanceAndPath documentation
  • Bugzilla 4641: Associative arrays of structs with alias this broken.
  • Bugzilla 4742: int % BigInt should work.
  • Bugzilla 4775: No substitution on writef("%%%s", "hi").
  • Bugzilla 4825: Regression(1.057, 2.040) "Error: non-constant expression" with -inline
  • Bugzilla 4866: Static-to-dynamic converted manifest constant array gets non-converted type in static/constraint if
  • Bugzilla 4869: auto return + inheritance + modules = compiler crashes(toctype.c)
  • Bugzilla 4873: Assertion failure: '0' on line 1483 in file 'expression.c'
  • Bugzilla 4882: std.traits hasUnsharedAliasing does not work for function type.
  • Bugzilla 4897: CodeView: No locals or parameters are shown when debugging, because of missing function info
  • Bugzilla 4890: GC.collect() deadlocks multithreaded program.
  • Bugzilla 4925: [ICE] segfault with module-scope assert(0)
  • Bugzilla 4926: ICE: PREC_zero assertion failure due to unset precedence
  • Bugzilla 4938: Regression(2.047) dmd segfault when compiling
  • Bugzilla 4941: Built-in tuple slice boundaries are not CTFE'd
  • Bugzilla 4949: ICE on invalid static if using value of 'this'
  • Bugzilla 4951: InternetAddress fails to resolve host when multithreading.
  • Bugzilla 4959: std.conv.parse error "no digits seen" on string starting with zero.
  • Bugzilla 4992: ICE(glue.c) or segfault: using int[new]
  • Bugzilla 5003: regex(replace with delegate) sample doesn't work.
  • Bugzilla 5026: ICE(expression.c) Incomplete mixin expression + char[] to char assignment
  • Bugzilla 5049: std.algortihm.bringToFront() returns wrong value.
  • Bugzilla 5052: take!(Take!R) should return Take!R, not Take!(Take!R).
  • Bugzilla 5071: passing value by ref to a function with an inner dynamic closure results in a wrong code
Version D 2.049 Sep 13, 2010

New/Changed Features

  • std.algorithm: reduce now works with non-range-based iteration, such as opApply.
  • std.numeric: Added FFT.
  • std.path: Changed sep, altsep etc. to manifest constants (enum).
  • std.process: Added environment, an AA-like interface for environment variables.
  • std.range: Iota, Stride, Transversal, FrontTransveral now support slicing where possible.
  • std.range: Added support for moveFront() and assignable elements in several higher-order ranges.
  • std.range: Added Lockstep, hasLvalueElements.
  • std.range: Added virtual function-based wrappers (InputRangeObject, OutputRangeObject) for when a binary interface to a range is required.
  • std.typecons: Added convenience functions for Rebindable.
  • std.traits: Added isAssignable, isIterable, ForeachType, isSafe, isUnsafe, EnumMembers.
  • std.traits: hasLocalAliasing, hasLocalObjects and hasLocalRawAliasing are now hasUnsharedAliasing, hasUnsharedObjects and hasUnsharedRawAliasing. Aliases to the old names are included for now for backwards compatibility.
  • std.typetuple: Added anySatisfy.
  • std.array: Modified Appender's interface to fix memory issues. Note that appending via ~= and using appender on the same array will not interleave anymore.
  • Bugzilla 2477: Trailing comma in array literal sometimes accepted, sometimes not

Bugs Fixed

  • Andrej Mitrovic updated the samples/d code
  • Unlisted Bug: std.math.pow doesn't work on immutable numbers.
  • Unlisted Bug: std.math.pow floating point overload expects both arguments to be exact same type.
  • Unlisted Bug: std.path.join("", "foo") returns "/foo" instead of "foo" on Posix.
  • Unlisted Bug: std.range.iota() random access primitives inconsistent after popFront on floating point version
  • Unlisted Bug: std.algorithm.findAdjacent() [...]
  • Bugzilla 190: Cannot forward reference typedef/alias in default value for function parameter
  • Bugzilla 1715: Template specialization checks for equality rather than convertibility
  • Bugzilla 1970: Templated interfaces not matched
  • Bugzilla 2511: Covariant return type doesn't work with circular import
  • Bugzilla 2716: Confusion of auto and scope as the class attribute
  • Bugzilla 2903: Splitter should be bi-dir if the input range is bi-dir.
  • Bugzilla 2951: std.random.dice() should be templated on proportions.
  • Bugzilla 2958: std.getopt RangeError on missing arg
  • Bugzilla 3046: Segfault with C++ static variable (Linux only)
  • Bugzilla 3123: std.algorithm.zip fails on 'lazy' ranges
  • Bugzilla 3294: forward reference to inferred return type of function call
  • Bugzilla 3312: std.string.count should use const(char)[], not immutable.
  • Bugzilla 3348: Documentation for many std.process functions has disappeared
  • Bugzilla 3361: code in std.zlib concatenates void[] arrays
  • Bugzilla 3418: link error with cast(ulong)(ulong*real)
  • Bugzilla 3544: optlink termination 0041338f with recursive nested functions
  • Bugzilla 3554: Ddoc generats invalid output for documentation comments with non paired paranthasis
  • Bugzilla 3627: -of with a filename with a double extension confuses linker
  • Bugzilla 3877: std.range.chain do not manage infinite ranges correctly
  • Bugzilla 3894: std.range.Stride!R requires R.front() and R.back() to return by reference
  • Bugzilla 3935: opBinary is instantiated with "="
  • Bugzilla 3946: schwartzSort - SwapStrategy always unstable
  • Bugzilla 3979: Order-of-compilation and forward reference errors
  • Bugzilla 3996: Regression(2.041) ICE(glue.c) Passing struct as AA template parameter (Algebraic with struct)
  • Bugzilla 4009: OPTLINK ruins the day yet again
  • Bugzilla 4173: Regression(2.037) Explicitly instantiated templates still try to do IFTI in some cases
  • Bugzilla 4177: __ctfe can't be used in pure functions
  • Bugzilla 4278: allow inlining of super calls (undo limitations of bug3500's fix)
  • Bugzilla 4291: Pure functions cannot access mixed in variables
  • Bugzilla 4292: CommonType fails for singular alias value.
  • Bugzilla 4302: Regression(2.046, 1.061): compiler errors using startsWith in CTFE
  • Bugzilla 4345: std.range.take!string: "Nonsensical finite range with slicing but no length".
  • Bugzilla 4346: More flexible std.array.array.
  • Bugzilla 4363: Some phobos ranges are not forward ranges (but should be).
  • Bugzilla 4381: Length attribute for std.typecons.Tuple.
  • Bugzilla 4387: std.range.Cycle assumes lvalue elements.
  • Bugzilla 4388: std.range.Radial assumes lvalue elements.
  • Bugzilla 4402: std.range.Zip doesn't work w/ non-lvalue ranges.
  • Bugzilla 4403: std.range.FrontTransversal assumes lvalue elements.
  • Bugzilla 4404: std.range.Transversal assumes lvalue elements.
  • Bugzilla 4408: Ambiguity when using std.algorithm.splitter with generic ranges.
  • Bugzilla 4430: Regression(2.037) erroneous matching on specialized template function
  • Bugzilla 4455: Taking the sqrt of an integer shouldn't require an explicit cast.
  • Bugzilla 4464: std.range.take does not always return Take!R.
  • Bugzilla 4518: to!string(enum w/invalid value) produces a somewhat unhelpful error
  • Bugzilla 4564: ICE on undefined variable in foreach over 0 .. undef
  • Bugzilla 4603: array(iota(1, 0)) error.
  • Bugzilla 4643: Shared values are unwritable.
  • Bugzilla 4645: to!string(const char*) in library causes Optlink to issue warning
  • Bugzilla 4652: Compiler hangs on template with zero-length tuple and another argument
  • Bugzilla 4655: Regression(1.063, 2.048) goto to a try block ICEs
  • Bugzilla 4676: Overload resolution rejects valid code when mixing variadics, non-variadics
  • Bugzilla 4681: Appender access violation
  • Bugzilla 4691: Incorrect comparison of double and long
  • Bugzilla 4700: to!float("0") fails
  • Bugzilla 4721: compilation slow when compiling unittests on dcollections
  • Bugzilla 4748: Shadowing declaration error in std.string.tolower
  • Bugzilla 4751: Regression(1.062, 2.047) ICE(constfold.c) >> after error
  • Bugzilla 4752: fail_compilation/fail345.d asserts in expression.c
  • Bugzilla 4771: fail_compilation/fail274.d hits a halt in iasm.c
  • Bugzilla 4789: std.algorithm.sort bug
  • Bugzilla 4810: dotProduct problem with ints
  • Bugzilla 4826: Regression(2.041) "cannot create associative array" and compiler crash
  • Bugzilla 4828: ICE w/ non-boolean dot expression sth.template_instance in static if
  • Bugzilla 4834: Implicit sharing via delegates in std.concurrency
Version D 2.048 Aug 8, 2010

New/Changed Features

  • std.complex: New Complex.toString() syntax.
  • std.string: icmp() now works with all built-in string types.
  • Bugzilla 4077: Bugs caused by bitwise operator precedence
  • Bugzilla 4080: Patch for building dynamic libraries on Mac OS X

Bugs Fixed

  • Unlisted Bug: std.algorithm.filter not a forward range
  • Unlisted Bug: std.algorithm.Uniq requires a bidirectional range
  • Unlisted Bug: std.algorithm.Uniq missing a save() function
  • Unlisted Bug: std.algorithm.Group missing a save() function
  • Unlisted Bug: std.traits.isAssociativeArray reports true for structs w/ keys, values properties
  • Unlisted Bug: gc_query returns 0 for attr when called on interior pointers
  • D/112964: capacity can return a value < length
  • Bugzilla 978: std.utf's toUTF* functions accept some invalid and reject some valid UTF
  • Bugzilla 996: Error in doc on implicit conversion between pointer and array
  • Bugzilla 1418: tupleof bug on nested classes
  • Bugzilla 1678: ref with varargs generates invalid code
  • Bugzilla 2275: std.utf.toUTF16z() should return const(wchar)*
  • Bugzilla 2627: std.traits.hasAliasing reports true for static arrays
  • Bugzilla 2872: Length, opIndex for Map
  • Bugzilla 2931: Initialization struct with array from another struct
  • Bugzilla 3202: std.math.pow cause dead loop
  • Bugzilla 3326: $ in delegate literal causes Access Violation
  • Bugzilla 3355: std.string.cmp works incorrectly for mixed-type and different-length strings
  • Bugzilla 3386: to!bool(string) is not implemented
  • Bugzilla 3436: std.functional.compose with only one function
  • Bugzilla 3439: std.range.Sequence.opIndex not consistent after calling popFront().
  • Bugzilla 3447: std.file uses unconventional file permissions
  • Bugzilla 3528: FreeBSD patches for druntime.
  • Bugzilla 3560: foreach over nested function generates wrong code
  • Bugzilla 3569: DMD Stack Overflow with a struct member function inside a C-style struct initializer
  • Bugzilla 3604: extern(C) callable function with array parameters broken
  • Bugzilla 3679: Regression(2.031) template forward reference regression
  • Bugzilla 3706: delegates of interfaces with multiple inheritance fail
  • Bugzilla 3716: Regression (2.037) with multi dimensional array literals
  • Bugzilla 3782: The POSIX sys/un.h header
  • Bugzilla 3853: core.sys.posix.stdio.pclose is missing
  • Bugzilla 3872: std.algorithm.filter could become bidirectional if its input range is bidir
  • Bugzilla 3874: std.range.stride assumes a bidirectional input range
  • Bugzilla 3917: opEquals for Ojbect could be more efficient
  • Bugzilla 3937: os.path.dirname fails on absolute path
  • Bugzilla 3961: Error with to!(somestruct)
  • Bugzilla 3983: Regression(2.037): struct with == can't be member of struct with template opEquals
  • Bugzilla 4109: (reopened) writeln doesn't work with empty static array
  • Bugzilla 4171: std.random.uniform does not work for a range of characters
  • Bugzilla 4191: [FreeBSD] real constants are rounded to double precision
  • Bugzilla 4198: [FreeBSD] imprecision in decimal floating-point literals
  • Bugzilla 4238: Segfault(statement.c): with(typeof(int))
  • Bugzilla 4260: windows & basename
  • Bugzilla 4267: forward reference error when 2-fold aliasing a template instance
  • Bugzilla 4303: __traits(compiles) returns wrong result when used recursively
  • Bugzilla 4305: Take, Chain on top of ranges w/o moveFront()
  • Bugzilla 4307: spawn()'ed thread doesn't terminate
  • Bugzilla 4314: Regression(1.062): Expression array1 && array2 doesn't compile
  • Bugzilla 4327: std.container.Array.Range.~this() tries to call free(T[])
  • Bugzilla 4339: Struct destructor + invariant + struct parameter = horrific error message
  • Bugzilla 4356: Copy constructor not called under extremely mysterious circumstances
  • Bugzilla 4362: std.range.repeat and cycle do not have a .save() method
  • Bugzilla 4363: std.algorithm.Until is not a forward range
  • Bugzilla 4369: Multiple bugs in GC minimize()
  • Bugzilla 4370: POSIX monitor attribute not being used
  • Bugzilla 4396: mkdir race prevents concurrent compiling with DMD using make -j
  • Bugzilla 4400: D2 GC doesn't allocate with 16 bytes alignment
  • Bugzilla 4406: Typo (bug) in std.concurrency
  • Bugzilla 4412: Array capacity growth spikey and the ratio approaches 1.0
  • Bugzilla 4443: Optimizer produces wrong code for || or && with struct arrays
  • Bugzilla 4452: Incorrect result of BigInt ^^ long
  • Bugzilla 4470: Problems with std.bigint mod and divide
  • Bugzilla 4503: forward reference to aliased template instance
  • Bugzilla 4506: Regression(2.034): -O flag breaks some recursive functions
  • Bugzilla 4514: Regression: Cannot cast from X* to X
  • Bugzilla 4516: Regression(2.040): forward declaration of enum not supported
  • Bugzilla 4551: D2 Language Docs: http://www.digitalmars.com/d/2.0/arrays.html
  • Bugzilla 4569: extern(c++) doesn't understand const types, produces bad mangled symbol
  • Bugzilla 4570: ElementType!(void[]) shows error message
  • Bugzilla 4578: Regression(2.047,1.062): ICE(cgcod.c): var+arr[]
  • Bugzilla 4590: Spec incorrectly describes array appending and memory stomping
Version D 2.047 Jun 11, 2010

New/Changed Features

  • Changed "op=" to just "op" for template argument to opOpAssign
  • std.algorithm: Added save() to forward ranges; added split() using only one element as separator; added indexOf; fixed unlisted bug in startsWith and endsWith; added skipOver(); added canFind().
  • std.array: Added implementation of save() for T[]s.
  • std.concurrency: Eliminated spurious unittest stdout messages.
  • std.container: Added.
  • std.conv: Added file and line information to conversion errors; added brackets '[' and ']' around arrays and associative arrays as defaults; added emplace() for non-class types.
  • std.file: Replaced exception upon out-of-memory error with assert(0).
  • std.functional: toDelegate now accepts callable(function pointers, delegates and objects implement opCall)
  • std.path: Made basename() generic in string type.
  • std.range: Added the existence of the property save as a condition for isForwardRange; added save to the range defined within; replaced a couple of awkward front() implementations; defined module-level moveFront() and range member moveFront() where appropriate; added @property maxLength to Take; arranged things such that take() for slice-able ranges returns the same type as the slice; eliminated SListRange; defined iota() with one argument; moved BinaryHeap within.
  • std.regex: Qualified indexOf with std.algorithm.
  • std.regexp: Qualified indexOf with std.algorithm.
  • std.stdio: Added an error message to enforce() in rawRead().
  • std.string: Improved indexOf(), tolower(), splitter(), chomp().
  • std.traits: Added templates to get compile-time information about functions.
  • std.typecons: Added AutoImplement.
  • std.utf: Eliminated decodeFront() and decodeBack() - they aren't needed since strings are bidirectional ranges.
  • Bugzilla 2008: Poor optimization of functions with ref parameters
  • Bugzilla 3793: Functions with static arrays as arguments are not inlined
  • Bugzilla 4296: Reduce parasitic error messages

Bugs Fixed

  • Bugzilla 1193: regression: "matches more than one template declaration" doesn't list the location of the conflicting templates
  • Bugzilla 1894: scope(exit) is ignored except in compound statements
  • Bugzilla 1941: missing line on inaccesable external private module member
  • Bugzilla 2127: inliner turns struct "return *this" from by-value into by-ref
  • Bugzilla 2276: Error message missing line number on array operation
  • Bugzilla 2546: Array Ops silently fail when no slice symbol is used.
  • Bugzilla 2738: Rebindable should work for interfaces.
  • Bugzilla 2835: std.socket.TcpSocket doesn't actually connect
  • Bugzilla 2881: x.stringof returns typeof(x).stringof when x is an enum
  • Bugzilla 3064: Invalid array operation accepted, generates bad code
  • Bugzilla 3088: std.xml.check() fails on xml comments
  • Bugzilla 3139: compiler dies "Error: out of memory" with case range
  • Bugzilla 3200: std.xml doesn't follow spec for Tag.text
  • Bugzilla 3323: Segfault or ICE(e2ir.c) using struct with destructor almost anywhere
  • Bugzilla 3398: Attributes inside a union screws data alignment
  • Bugzilla 3465: isIdeographic can be wrong in std.xml
  • Major improvements to CustomFloat, fixing Bugzilla 3520: std.numeric.CustomFloat horribly broken
  • Bugzilla 3538: Default value of alias template parameter is instantiated only once.
  • Bugzilla 3547: for option -od for relative path the path is added twice
  • Bugzilla 3548: ICE occurs when an array is returned from a function is incorrectly used in an array op expression.
  • Bugzilla 3604: extern(C) callable function with array parameters broken
  • Bugzilla 3651: mangleof broken for enums
  • Bugzilla 3653: Problem sorting array of Rebindable
  • Bugzilla 3658: Crashing on vector operations (Mac only)
  • Bugzilla 3662: Wrong compile error within struct constructor and C-style initializer
  • Bugzilla 3667: Regression(D2 only): broken out(result) in contracts
  • Bugzilla 3786: bug in std.string.removechars
  • Bugzilla 3854: Error on static initialization of arrays with trailing comma.
  • Bugzilla 3873: std.range.repeat should have popBack defined
  • Bugzilla 3876: std.range.Take back/popBack methods don't work correctly
  • Bugzilla 3880: std.regex functions with const/immutable Regex object
  • Bugzilla 4003: The result changes only with the order of source files.
  • Bugzilla 4045: [CTFE] increasing array length
  • Bugzilla 4052: [CTFE] increment from array item
  • Bugzilla 4056: Template instantiation with bare parameter not documented
  • Bugzilla 4073: core.cpuid crashes
  • Bugzilla 4078: [CTFE] Failed return of dynamic array item
  • Bugzilla 4084: Ignored missing main() closing bracket
  • Bugzilla 4109: writeln doesn't work with empty static array
  • Bugzilla 4143: fix warnings in dmd build
  • Bugzilla 4156: Segfault with array+=array
  • Bugzilla 4169: building dmd with a modern gcc produces a buggy compiler
  • Bugzilla 4175: linux.mak doesn't declare sufficient dependencies to support parallel builds
  • Bugzilla 4188: std.file.remove throws Exception on success
  • Bugzilla 4193: Regression 2.046, ICE(expression.c): initialising class member with const forward reference
  • Bugzilla 4202: Changset 1517 doesn't compile
  • Bugzilla 4207: std.cover.setDestDir does not work.
  • Bugzilla 4208: druntime should not depend on Phobos
  • Bugzilla 4212: DWARF: void arrays cause gdb errors
  • Bugzilla 4213: Strange behaviour with static void[] arrays
  • Bugzilla 4219: hasAliasing does not care about immutable
  • Bugzilla 4220: I cannot apply @safe to intrinsic operation(eg: std.math.sqrt)
  • Bugzilla 4228: std.array.replace contains 2 bugs
  • Bugzilla 4230: version(unittest)
  • Bugzilla 4231: Solitary opUnary Postincrement and Postdecrement user defined operators are broken.
  • Bugzilla 4242: ICE(module.c): importing a module with same name as package
  • Bugzilla 4249: std.regex fails to compile with debug=regex
  • Bugzilla 4252: [CTFE] No array bounds checking in assignment to char[] array
  • Bugzilla 4257: ICE(interpret.c): passing parameter into CTFE as ref parameter
  • Bugzilla 4259: Header generation omits leading '@' for properties
  • Bugzilla 4262: Header generation omits 'enum' for enum declarations
  • Bugzilla 4263: Header generation omits '@system' attribute
  • Bugzilla 4270: Missing line number in 'can only catch class objects' error message
  • Bugzilla 4300: BigInt * int doesn't work well
Version D 2.046 May 10, 2010

New/Changed Features

  • Add hints for missing import declarations.
  • Speed up compilation.
  • All length methods in Phobos are now a @property.
  • Bugzilla 1001: print stack trace (in debug mode) when program die

Bugs Fixed

  • Fix hanging problem on undefined identifiers.
  • Bugzilla 461: Constant not understood to be constant when circular module dependency exists.
  • Bugzilla 945: template forward reference with named nested struct only
  • Bugzilla 1055: union forward reference "overlapping initialization" error
  • Bugzilla 2085: CTFE fails if the function is forward referenced
  • Bugzilla 2386: Array of forward referenced struct doesn't compile
  • Bugzilla 3945: AssertExpression message should implicitly convert to const char[]
  • Bugzilla 4015: forward reference in alias causes error
  • Bugzilla 4016: const initializer cannot forward reference other const initializer
  • Bugzilla 4042: Unable to instantiate a struct template.
  • Bugzilla 4100: Break and continue to label should mention foreach
  • Bugzilla 4116: object.di does not match object_.d
  • Bugzilla 4146: Unavailable: core.sys.posix.sys.wait.waitid()
  • Bugzilla 4184: associative array with certain key types results in corrupt values during iteration
Version D 2.045 May 4, 2010

New/Changed Features

Bugs Fixed

  • Another try at fixing the Dwarf issues.
Version D 2.044 Apr 30, 2010

New/Changed Features

  • Improve spelling checking distance to 2.
  • Now all unittests are run, even if some fail
  • Many small improvements to error diagnostics and recovery

Bugs Fixed

  • Bugzilla 1079: gdb: Dwarf Error: Cannot find DIE at 0xb705 referenced from DIE at 0x250
  • Bugzilla 2437: ICE(tocsym.c, !needThis()) - default struct argument
  • Bugzilla 2935: ICE(out.c) using struct with constructor as function default argument
  • Bugzilla 2549: Segfault on array multiplication.
  • Bugzilla 3066: Array operation without a slice as the lvalue accepted, bad codegen
  • Bugzilla 3207: gdb: Push D patches upstream
  • Bugzilla 3415: broken JSON output
  • Bugzilla 3522: ICE(cg87.c): variable*array[].
  • Bugzilla 3987: [gdb] Invalid DWARF output for function pointers
  • Bugzilla 3974: ICE(init.c): Static array initializer with more elements than destination array
  • Bugzilla 4036: Segfault with -inline and literal of struct containing union
  • Bugzilla 4037: [gdb] Invalid DWARF output for wchar
  • Bugzilla 4038: [gdb] Invalid DWARF output for function pointers with ref args
  • Bugzilla 4067: [CTFE] Code inside try-catch blocks is silently ignored
  • Bugzilla 4072: Stack overflow on recursive template expansion inside contract
  • Bugzilla 4081: cannot compile the dmd on FreeBSD 8
  • Bugzilla 4089: crash when creating JSON output for incomplete struct
  • Bugzilla 4093: Segfault(interpret.c): with recursive struct templates
  • Bugzilla 4105: Stack overflow involving alias template parameters and undefined identifier
  • Bugzilla 4108: ICE(cod2.c): zero-length static array in function call
  • Bugzilla 4118: std.conv.to!SomeStruct("hello") crashes compiler
  • Bugzilla 4131: break does not work correctly with foreach and associative arrays
Version D 2.043 Apr 6, 2010

New/Changed Features

  • .init property for static arrays is now an array literal
  • Improved speed of associative arrays
  • std.bigint has been completely replaced with a faster implementation. Multiplication is now 5 times faster, division is 300 times faster, and squaring is 10 times faster. For large numbers (~5000 words), the speedup is 5 times larger than this.

Bugs Fixed

  • Fixed memory corruption problem with array appends
  • Bugzilla 122: DDoc newline behaviour produces suboptimal results
  • Bugzilla 1628: Ddoc produces invalid documentation for --- blocks
  • Bugzilla 2609: No documentation generated for destructor
  • Bugzilla 3808: Assertion Failure : Assertion failure: 'classinfo->structsize == CLASSINFO_SIZE' on line 870 in file 'toobj.c'
  • Bugzilla 3884: Segfault: defining a typedef with an invalid object.d
  • Bugzilla 3911: Associative array in CTFE crashes compiler
  • Bugzilla 3958: mixin(non-static method) crashes compiler
  • Bugzilla 3972: Regarding module with name different from its file name
  • Bugzilla 3984: Segfault(interpret.c): CTFE using struct constructor on a local static variable
  • Bugzilla 3986: Struct constructors bypass default initialization of member variables
  • Bugzilla 4002: dmd.conf and binary path in dmd -v output
  • Bugzilla 4004: DMD 2.042 CTFE regression with functions taking ref parameters
  • Bugzilla 4005: std.c.stdlib.exit in CTFE and more
  • Bugzilla 4011: Incorrect function overloading using mixins
  • Bugzilla 4019: [CTFE] Adding an item to an empty AA
  • Bugzilla 4020: [ICE][CTFE] struct postblit in CTFE
  • Bugzilla 4023: std.math.hypot() returns infinity when either argument is zero
  • Bugzilla 4027: Closures in CTFE generate wrong code
  • Bugzilla 4029: CTFE: cannot invoke delegate returned from function
Version D 2.042 Mar 19, 2010

New/Changed Features

Bugs Fixed

  • Add base class destruction to clear() in object.d
  • Bugzilla 3842: ICE(expression.c) using pointer in CTFE
  • Bugzilla 3885: No multithread support for Windows DLL
  • Bugzilla 3899: CTFE: poor error message for use of uninitialized variable
  • Bugzilla 3900: CTFE: Wrong return value for array.var assignment
  • Bugzilla 3901: PATCH: Nested struct assignment for CTFE
  • Bugzilla 3902: Definition of opCmp
  • Bugzilla 3912: pure static nested functions are not recognized as pure
  • Bugzilla 3914: Struct as argument that fits in register has member accessed wrong
  • Bugzilla 3919: ICE(expression.c, 9944): * or / with typedef ireal
  • Bugzilla 3920: Assertion failure: '0' on line 10018 in file 'expression.c'
  • Bugzilla 3930: AAs horribly broken
Version D 2.041 Mar 7, 2010

New/Changed Features

  • __traits allMembers and and derivedMembers now return a tuple of strings rather than an array of strings. Enclose __traits in [ ] to make array literal. This makes it possible for foreach statements to iterate at compile time over it.
  • Interface member functions can now have contracts.
  • Added new operator overloading regime.
  • Warnings no longer halt the parsing/semantic passes, though they still return an error status and still do not generate output files. They also no longer count as errors when testing with "compiles" traits.
  • Added -wi switch for Bugzilla 2567
  • Mixin template definitions should be preceded with mixin
  • Add !in operator.
  • Associative array contents can now be compared for equality
  • Use of length inside of [ ] is now deprecated, use $ instead
  • Added toDelegate() to std.functional to convert function pointers to delegates.
  • Implemented attributes for constructors.
  • Implemented qualifiers for struct literals, like immutable(S)(1,2,3)
  • Array equality can now be done with differing array element types.
  • Add simple spell checking.
  • Bugzilla 3378: [tdpl] ++x should be an lvalue
  • string, wstring are now bidirectional (not random) ranges
  • std.algorithm: defined move with one argument; levenshtein distance generalized to with all forward ranges; take now has swapped arguments
  • std.array: empty for arrays is now a @property; front and back for a string and wstring automatically decodes the first/last character; popFront, popBack for string and wstring obey the UTF stride
  • std.conv: changed the default array formatting from "[a, b, c]" to "a b c"
  • std.range: swapped order of arguments in take
  • std.stdio: added readln template
  • std.variant: now works with statically-sized arrays and const data
  • std.traits: added isNarrowString
  • The default type for [1,2,3] is now int[] rather than int[3].

Bugs Fixed

  • Bugzilla 2321: spec on inline asm can be misunderstood
  • Bugzilla 2463: No line number in "statement is not reachable" warning
  • Bugzilla 3029: Bug in array value mangling rule
  • Bugzilla 3306: bad function/delegate literal generated into header files
  • Bugzilla 3373: bad codeview debug info for long and ulong
  • Posix only, Bugzilla 3420: [PATCH] Allow string import of files using subdirectories
  • Bugzilla 3450: incorrect result for is (typeof({ ... }())) inside a struct
  • Bugzilla 3453: Linking order affects proper execution (Mac OSX only)
  • Bugzilla 3491: typeof((string[string]).init) == AssociativeArray!(string, string), doesn't implicitly convert to string[string].
  • Bugzilla 3500: super behaves differently with -inline
  • Bugzilla 3558: Optimizer bug results in false if condition being taken
  • Bugzilla 3582: core.stdc.ctype functions are not pure
  • Bugzilla 3619: Thread crash on exit
  • Bugzilla 3637: Array append patch to prevent stomping and to enhance thread-local append performance
  • Bugzilla 3644: Wrong UCHAR_MAX value in module core.stdc.limits
  • Bugzilla 3670: Declarator grammar rule is broken
  • Bugzilla 3689: Grammar does not allow const(int)
  • Bugzilla 3692: ICE(mtype.c) with associative arrays when std.variant is imported
  • Bugzilla 3695: __EOF__ token not documented
  • Bugzilla 3697: StructTemplateDeclaration and others missing constraint in rule
  • Bugzilla 3710: Typo in allMembers description?
  • Bugzilla 3736: corrupted struct returned by function with optimizations (-O)
  • Bugzilla 3737: SEG-V at expression.c:6255 from bad opDispatch
  • Bugzilla 3763: std.stdio.readlnImpl absurdly inefficient and overflows stack
  • Bugzilla 3768: reapeted quotes in ddoc.html
  • Bugzilla 3769: Regression: Segfault(constfold.c) array literals and case statements
  • Bugzilla 3775: Segfault(cast.c): casting no-parameter template function using property syntax
  • Bugzilla 3776: Wrong CHAR_MIN value in module core.stdc.limits
  • Bugzilla 3781: ICE(interpret.c): using no-argument C-style variadic function in CTFE
  • Bugzilla 3803: compiler segfaults
  • Bugzilla 3840: Jump to: section in the docs should be sorted
Version D 2.040 Jan 29, 2010

New/Changed Features

  • Clarification: function returns are not lvalues
  • Added shared static constructors/destructors, regular static constructors/destructors now deal with TLS
  • Add -map command line switch
  • Add @disable attribute
  • Delegates and function pointers may be used in CTFE
  • Delegate literals and function literals may be used in CTFE
  • Lazy function parameters may now be used in CTFE
  • Slicing of char[] arrays may now be used in CTFE
  • added static/final function implementations to interfaces
  • added getOverloads, identifier, and isStaticFunction traits.
  • ModuleInfo changed from class to struct
  • Bugzilla 3556: version(CTFE)
  • Bugzilla 3728: getOverloads and identifier traits

Bugs Fixed

  • Added TLS support for OSX
  • Bugzilla 47: Internal error: cg87 3316
  • Bugzilla 1298: CTFE: tuple foreach bugs
  • Bugzilla 1790: CTFE: foreach(Tuple) won't compile if Tuple contains string
  • Bugzilla 2101: CTFE: Please may I use mutable arrays at compile time?
  • Bugzilla 2066: to!(string)(int) into CTFE-compatible
  • Bugzilla 3488: Segfault(expression.c): enum declared with struct static initializer
  • Bugzilla 3535: struct constructors don't work in CTFE
  • Bugzilla 3552: ICE(mtype.c): declaring a variable called 'AssociativeArray' then using an AA.
  • Partial fix for Bugzilla 3569, stops the stack overflow
  • Bugzilla 3600: template instantiation with empty tuple
  • Bugzilla 3660: Templates and shared functions don't mix
  • Bugzilla 3668: foreach over typedef'd array crashes dmd
  • Bugzilla 3671: x^^3 gives wrong result when x is a floating-point literal
  • Bugzilla 3674: forward reference error with multiple overloads with same name
  • Bugzilla 3675: Regression: Struct literals cannot be initialized with another struct literal
  • Bugzilla 3687: Array operation "slice times scalar" tramples over memory
  • Bugzilla 3719: forward references can cause out-of-memory error
  • Bugzilla 3723: Regression: forward referenced enum
  • Bugzilla 3724: bug in Expression::arraySyntaxCopy (null pointer dereference on struct->union->struct)
  • Bugzilla 3726: Regression: ICE(mangle.c 81): struct forward reference with static this
  • Bugzilla 3727: lots of "deffering SomeStructName" messages when compiling
  • Bugzilla 3734: [patch] src/traits.c does not compile with gcc (Ubuntu 4.4.1-4ubuntu8) 4.4.1
  • Bugzilla 3740: Regression: class with fwd reference of a nested struct breaks abstract
Version D 2.039 Jan 1, 2010

New/Changed Features

Bugs Fixed

  • Bugzilla 3663: struct forward reference regresssion
  • Bugzilla 3664: struct forward declaration causes enum to conflict with itself
Version D 2.038 Dec 30, 2009

New/Changed Features

  • Added core.cpuid in Druntime
  • Bugzilla 3514: opApply should be the first-choice foreach iteration method.
  • Bugzilla 3577: Wrong precedence for opPow
  • Added auto ref functions
  • Added function template auto ref parameters
  • Added isRef, isOut and isLazy to __traits
  • Transporting return type from args to return type, see DIP2

Bugs Fixed

  • Bugzilla 45: Internal error: cgcod 1594
  • Bugzilla 46: Constant folding with long doubles
  • Bugzilla 282: Bizarre circular import nested name invisibility issue
  • Bugzilla 390: Cannot forward reference enum nested in struct
  • Bugzilla 400: forward reference error; no propety X for type Y (struct within struct)
  • Bugzilla 1160: enums can not be forward referenced
  • Bugzilla 1564: Forward reference error for enum in circular import
  • Bugzilla 2029: Typesafe variadic functions don't work in CTFE
  • Bugzilla 2816: Sudden-death static assert is not very useful
  • Bugzilla 3270: pure functions returning struct
  • Bugzilla 3443: Thread.thread_needLock() should be nothrow
  • Bugzilla 3455: Some Unicode characters not allowed in identifiers
  • Bugzilla 3458: int fsync(int) commented out in core.sys.posix.unistd
  • Bugzilla 3476: C-style initializer for structs must be disallowed for structs with a constructor
  • Bugzilla 3575: CTFE: member structs not initialized correctly
  • Bugzilla 3583: Unsigned right shift works the same as signed right shift.
  • Bugzilla 3584: DeclDef rule is missing entries
  • Bugzilla 3585: Duplicate clauses in EqualExpression and RelExpression rules
  • Bugzilla 3587: Aggregate rule references undefined Tuple
  • Bugzilla 3588: WithStatement rule references unspecified Symbol
  • Bugzilla 3589: BaseClassList and InterfaceClasses rules are incorrect, missing ','
  • Bugzilla 3590: FunctionParameterList rule is missing
  • Bugzilla 3591: TemplateIdentifier rule is misspelled
  • Bugzilla 3592: ClassTemplateDeclaration and FunctionTemplateDeclaration rules are unreferenced
  • Bugzilla 3593: IntegerExpression rule unspecified
  • Bugzilla 3594: AsmPrimaryExp rule references unspecified rules
  • Bugzilla 3595: Several rules are missing ':' after rule name
  • Bugzilla 3596: Need alias for using std.algorithm.remove
  • Bugzilla 3601: Debug and Release builds of DMD produce different object files
  • Bugzilla 3611: Enum forward referencing regression
  • Bugzilla 3612: ExpressionList is undefined
  • Bugzilla 3617: CTFE: wrong code for if(x) where x is int or smaller
  • Bugzilla 3621: implicit conversion to const rules need tightening
  • Bugzilla 3633: Optimizer causes access violation
  • Bugzilla 3641: alias shared T U does not work
  • Bugzilla 3645: manifest constant (enum) crashes dmd
  • Bugzilla 3647: non-function opDispatch crashes dmd
Version D 2.037 Dec 3, 2009

New/Changed Features

  • Conditional expressions ?: can now be modifiable lvalues.
  • The type inferred from an ArrayLiteral is now a dynamic array, not a static one.
  • Added support for op= for array.length
  • Array and associative array types are now determined by using ?: across all the elements, not just using the first one.
  • Array concatenation with elements now allows implicit conversion of the elements to the array element type.
  • No more comma operators allowed between [ ].
  • ClassInfo now merged into TypeInfo_Class.
  • Bugzilla 3379: [tdpl] Parameter names not visible in the if clause of a template
  • Bugzilla 3380: [tdpl] typeid(obj) should return the dynamic type of the object
  • Removed -safe command line switch, added -noboundscheck command line switch.
  • Bugzilla 3481: PATCH: opPow(), x ^^ y as a power operator
  • Added opDispatch
  • properties can only have 0 or 1 arguments
  • properties cannot be overloaded with non-properties
  • std.math: Added FloatControl, IeeeFlags for enabling floating-point exceptions.
  • std.math: Inverse trig functions are now pure nothrow.

Bugs Fixed

  • std.array: Fixed unlisted bug in array().
  • Bugzilla 111: appending a dchar to a char[]
  • Bugzilla 2664: OSX standard math functions are less accurate
  • Bugzilla 2802: VariantN.opCmp!(T) fails when T != VariantN
  • Bugzilla 2967: spec does not mention that inline asm is a valid "return" statement
  • Bugzilla 2977: std.random.unpredictableSeed() should use thread ID somewhere
  • Bugzilla 3115: >>> and >>>= generate wrong code
  • Bugzilla 3171: % not implemented correctly for floats
  • Bugzilla 3311: std.range.chain shouldn't have opIndexAssign if arguments aren't mutable
  • Bugzilla 3375: [tdpl] Ternary operator doesn't yield an lvalue
  • Bugzilla 3381: [tdpl] Incorrect assessment of overriding in triangular-shaped hierarchy
  • Bugzilla 3388: [tdpl] contracts should allow throw expressions
  • Bugzilla 3390: [tdpl] out(result) contract should not be able to rebind result
  • Bugzilla 3407: [tdpl] Compiling with -safe -release must keep all bound checks
  • Bugzilla 3433: [tdpl] Comparing structs for equality is not member-by-member
  • Bugzilla 3469: ICE(func.c): Regression. Calling non-template function as a template, from another module
  • Bugzilla 3478: "no effect in expression" error on return to void
  • Bugzilla 3494: Segfault(mtype.c) using typeof(return) inside an auto function
  • Bugzilla 3495: Segfault(typinf.c) instantiating D variadic function with too few arguments
  • Bugzilla 3496: ICE(cgelem.c, optimizer bug) cast(void *)(x&1)== null.
  • Bugzilla 3502: Fix for dropped Mac OS X 10.5
  • Bugzilla 3521: Optimized code access popped register
  • Bugzilla 3540: Another DWARF line number fix
  • Bugzilla 3551: nested struct => dmd adds a hidden pointer
  • Bugzilla 3553: ICE when a function argument defaults to __LINE__
Version D 2.036 Nov 5, 2009

New/Changed Features

  • Static arrays are now passed by value to functions rather than by reference
  • std.algorithm: Add hasLength requirement to topN; implemented topN for two non-adjacent ranges; added replaceTop function to BinaryHeap; changed BinaryHeap.top to return ref.
  • std.ctype: Add pure to isalnum, isalpha, iscntrl, isdigit, islower, ispunct, isspace, isxdigit, isgraph, isprint, isascii, toupper.
  • std.date: Implementation change and unittest for isLeapYear and daysInYear. Made both pure as well.
  • std.encoding: Added function count().
  • std.md5: Added explicit pass-by-ref for fixed-size buffers.
  • std.numeric: Added gcd.
  • std.random: Added static checks for the parameters of the linear congruential generator.
  • std.range: Reinstated some unittests; fixed Cycle to work with the new fixed-size arrays.
  • std.typecons: Added alias 'expand' for Tuple.field.
  • std:utf: Added count function and changed the encode function to take fixed-size array by reference.
  • Bugzilla 3446: Rename float.min to float.min_normal

Bugs Fixed

  • std.range: Fixed unlisted bug in Transposed.
  • Problem with complicated array op expressions
  • Bugzilla 195: DDoc generates bad output when example contains "protected" attribute
  • Bugzilla 424: Unexpected OPTLINK Termination at EIP=0044C37B (too many fixups)
  • Bugzilla 1117: ddoc generates corrupted docs if code examples contain attributes with colons
  • Bugzilla 1812: DDOC - Unicode identifiers are not correctly marked.
  • Bugzilla 2694: alias pure nothrow XXX; is not pure nothrow!
  • Bugzilla 2862: ICE(template.c) using type tuple as function argument
  • Bugzilla 3035: cannot have const/invariant out parameter of type shared
  • Bugzilla 3102: Incorrectly matching type as shared (two cases with is expressions)
  • Bugzilla 3269: pure functions silently become nothrow
  • Bugzilla 3292: ICE(todt.c) when using a named mixin with an initializer as template alias parameter
  • Bugzilla 3349: typeid(shared(T)) generates wrong value
  • Bugzilla 3367: Regression: struct initialization no longer supports ctor overloads
  • Bugzilla 3397: Unintended function call to static opCall
  • Bugzilla 3401: Compiler crash on invariant + method overload
  • Bugzilla 3422: ICE(cgcod.c) Structs with default initializers bigger than register size cannot be default parameters
  • Bugzilla 3423: Destructor and postblit don't get copied to the header file when using -H
  • Bugzilla 3426: ICE(optimize.c): struct literal with cast, as function default parameter.
  • Bugzilla 3429: Core dump on passing template literal to member function.
  • Bugzilla 3432: ICE(e2ir.c): casting template expression
Version D 2.035 Oct 14, 2009

New/Changed Features

  • Use -X to generate JSON files.

Bugs Fixed

  • Fold in patch from Bugzilla 1170
  • Bugzilla 1534: Can't mix in a case statement.
  • Bugzilla 2423: Erroneous unreachable statement warning
  • Bugzilla 2826: failed assignment gives wrong line number
  • Bugzilla 3190: enum doesn't work as the increment in a for loop
  • Bugzilla 3316: Functions nested in a pure templated function cannot reference its local variables
  • Bugzilla 3352: RangeError in std.conv
  • Bugzilla 3385: `std.string.split` requires a mutable array
  • Bugzilla 3392: a cast of this to void in tango.core.Thread is not allowed
Version D 2.034 Oct 11, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 258: Undefined identifier error for circular import
  • Bugzilla 1140: ICE(cod1.c) casting last function parameter to 8 byte value
  • Bugzilla 1592: dmd fail to resolve class symbol when i put files in a package
  • Bugzilla 2687: ICE(statement.c): tuple foreach in an erroneous template.
  • Bugzilla 2773: ICE(go.c) array assignment through a pointer, only with -O.
  • Bugzilla 2829: ICE(expression.c) static array block-initialized in struct literal
  • Bugzilla 3006: ICE(e2ir.c, tocsym.c) template module using array operation
  • Bugzilla 3041: Array slices can be compared to their element type: bad codegen or ICE
  • Bugzilla 3042: Segfault on incorrect override
  • Bugzilla 3101: Stack overflow: declaring aggregate member twice with static if
  • Bugzilla 3119: Segfault(expression.c) template function overloads with function with same name in other module
  • Bugzilla 3174: ICE(mtype.c): Compiler crash or compiler error with auto returns and const / immutable / invarient / pure
  • Bugzilla 3176: Compiler hangs on poorly formed mixin in variadic template
  • Bugzilla 3261: compiler crash with mixin and forward reference
  • Bugzilla 3286: Default parameter prevents to resolve inter-module circular dependency
  • Bugzilla 3301: Undefined identifier error dependent on order of imports when a circular import is involved
  • Bugzilla 3325: ICE(func.c) function literal with post-contract
  • Bugzilla 3343: Crash by "auto main(){}"
  • Bugzilla 3344: ICE(e2ir.c) returning an invalid function from main()
  • Bugzilla 3357: ICE(cod1.c) using 'in' with a static char array as AA key
  • Bugzilla 3366: Segfault(declaration.c) variadic template with unmatched constraint
  • Bugzilla 3374: [tdpl] ICE(init.c): Associative array type not inferred
Version D 2.033 Oct 5, 2009

New/Changed Features

  • Phobos is now using the Boost 1.0 license
  • Compiler now detects some cases of illegal null dereferencing when compiled with -O
  • The result type of the typeid(type) is now the most derived TypeInfo class, rather than the TypeInfo base class
  • Bugzilla 2905: Faster +-*/ involving a floating-pointing literal
  • Improved performance of int-to-string conversion

Bugs Fixed

  • gdb stack trace should work now
  • Bugzilla 302: in/out contract inheritance yet to be implemented
  • Bugzilla 718: ICE(cgcod.c) with int /= cast(creal)
  • Bugzilla 814: lazy argument + variadic arguments = segfault
  • Bugzilla 1168: Passing a .stringof of an expression as a template value parameter results in the string of the type
  • Bugzilla 1253: array initializers as expressions are not allowed in const arrays
  • Bugzilla 1571: Segfault(class.c) const on function parameters not carried through to .di file
  • Bugzilla 1731: forward reference of function type alias resets calling convention
  • Bugzilla 2202: Error getting type of non-static member of a class
  • Bugzilla 2469: ICE(cod1.c) arbitrary struct accepted as struct initializer
  • Bugzilla 2697: Cast of float function return to ulong or uint gives bogus value
  • Bugzilla 2702: Struct initialisation silently inserts deadly casts
  • Bugzilla 2839: ICE(cgcs.c) with int /= imaginary
  • Bugzilla 2970: std.path.join with version(Windows)
  • Bugzilla 2998: ICE(expression.c) with floating point enum
  • Bugzilla 3049: ICE(cod4.c) or segfault: Array operation on void[] array
  • Bugzilla 3059: Nonsensical complex op= should be illegal
  • Bugzilla 3132: std.string.split should be templated on mutable/const/immutable - closing again after the reopening on 2009-09-03 07:56:25 PDT
  • Bugzilla 3160: ICE(cgcod.c 1511-D1) or bad code-D2 returning string from void main
  • Bugzilla 3173: ICE(mtype.c) on wrong code (double to long to int conversion)
  • Bugzilla 3288: conv.d: using to with const int or long fails to compile.
  • Bugzilla 3300: std.string.toupper and tolower should be (const(char)[]), not string
  • Bugzilla 3304: Segfault using 'is' with a pointer enum.
  • Bugzilla 3305: Segfault(expression.c) with recursive struct template alias expressions
  • Bugzilla 3333: std.conv.to!(string, const int) error: cannot modify const
  • Bugzilla 3335: minor warning cleanups
  • Bugzilla 3336: ICE(glue.c) declaring AA with tuple key, only with -g
  • Bugzilla 3340: std.string.split(S1 s, S2 delim) still doesn't work for char[]
  • Bugzilla 3353: storage class of a member function is propagated to default arguments
  • (unlisted): std.algorithm: bug in reduce when passed const arguments
  • (unlisted): std.stdio: fixed documentation example
  • (unlisted): std.utf: fixed decodeFront and decodeBack
Version D 2.032 Sep 2, 2009

New/Changed Features

  • Improved exception message for assert(0) in Windows -release builds
  • Added support for:
    a[i].var = e2
    and:
    a[] = e
    in CTFE. (thanks, Don!)
  • Member functions can now be used in CTFE
  • Operator overloading can now be used in CTFE
  • Nested functions can now be used in CTFE
  • CTFE error messages now explain why the function could not be interpreted at compile time
  • synchronized member functions now implicitly typed as shared.
  • std.algorithm: added minPos
  • std.format: added raw specifier for reading
  • added File.byChunk
  • std.algorithm: added more unittests and checks for user-based comparison passed to topN
  • std.math: replaced std.c with core.stdc; improved approxEqual to work with ranges, not only numbers or arrays
  • std.range: defined Take.popBack whenever sensible; improved iota to accept negative ranges and steps

Bugs Fixed

  • Bugzilla 601: statement.html - Formatting/markup errors in BNF
  • Bugzilla 1461: Local variable as template alias parameter breaks CTFE
  • Bugzilla 1600: Functions taking only one array cannot be called with property syntax
  • Bugzilla 1604: Non-final method on final struct is too restrictive (closed with "invalid" advise)
  • Bugzilla 1605: break in switch with goto breaks in ctfe
  • Bugzilla 1616: std/metastrings.d
  • Bugzilla 1940: Phobos buildscripts do not work on x86_64
  • Bugzilla 1948: CTFE fails when mutating a struct in an array
  • Bugzilla 1950: CTFE doesn't work correctly for structs passed by ref
  • Bugzilla 1969: ICE(cod1.c) using undefined operator with one const operand
  • Bugzilla 1972: Foreach range statement breaks CTFE
  • Bugzilla 2150: cannot get values from const variant
  • Bugzilla 2277: array ops and const arrays incompatible
  • Bugzilla 2398: writef("%x") for a pointer is always uppercase
  • Bugzilla 2560: ICE(cod4.c) on invoking method that takes ref const struct parameter
  • Bugzilla 2564: CTFE: the index in a tuple foreach is uninitialized (bogus error)
  • Bugzilla 2569: static arrays in CTFE functions don't compile
  • Bugzilla 2575: gdb can not show code
  • Bugzilla 2587: std.process.shell doesn't work for win32
  • Bugzilla 2604: DW_TAG_module and GDB
  • Bugzilla 2665: ICE(cod4.c) on certain const struct function return types
  • Bugzilla 2784: Interfaces should be able to require type definitions (closed with "invalid" advise)
  • Bugzilla 2785: Interfaces should be able to require non-member functions (closed with "invalid" advise)
  • Bugzilla 2786: Interfaces should be able to require constructors (closed with "invalid" advise)
  • Bugzilla 2882: std.random.MersenneTwisterEngine without no seed
  • Bugzilla 2925: Destructor not called
  • Bugzilla 2937: postblit not called for foreach arg over array of structs
  • Bugzilla 2940: null is null cannot be evaluated at compile time
  • Bugzilla 2976: rename retreatN to retreat
  • Bugzilla 2979: Xml tags with only attributes return as without attributes ElementParser.parse
  • Bugzilla 2980: compiler error when writefln( uint )
  • Bugzilla 2987: D2 phobos BigInt opMul doesn't work correctly
  • Bugzilla 2988: Chain needs opIndexAssign.
  • Bugzilla 2989: std.typetuple: add support for any static tuples
  • Bugzilla 2992: (closed with "later" advise)
  • Bugzilla 2996: std.typetuple: add support for any static tuples
  • Bugzilla 3000: iota should work with floats
  • Bugzilla 3017: doc errors in std.range (on behalf of Steven Schveighoffer)
  • Bugzilla 3025: uniform(float,float) pops first, uniform(int,int) pops last
  • Bugzilla 3037: Off-by-one error in Stride.length
  • Bugzilla 3039: -vtls compiler flag not listed in man file
  • Bugzilla 3058: [CTFE] Cannot return out of foreach range statement
  • Bugzilla 3074: std.conv.to!(string)(int.min)
  • Bugzilla 3077: 3077 crash exiting main() without result code
  • Bugzilla 3087: std.range.retro.opIndex out of range
  • Bugzilla 3098: std.algorithm.reduce example can not compile
  • Bugzilla 3100: ICE(cast.c) struct with members is shared
  • Bugzilla 3132: std.string.split should be templated on mutable/const/immutable
  • Bugzilla 3148: syntax error using invariant
  • Bugzilla 3153: win32.mak tries to copy phobos.lib, gcstub.obj to nonexistent folder lib
  • Bugzilla 3162: can't fully use compile-time floats as template parameters
  • Bugzilla 3165: What kind of integer division does D use?
  • Bugzilla 3166: "positive" -> "non-negative" in modulo operator description
  • Bugzilla 3169: Segfault(cast.c) dividing ulong by int
  • Bugzilla 3170: Forward reference of nested class fails if outer class is not plain
  • Bugzilla 3183: Spec of align attribute needs work
  • Bugzilla 3184: std.algorithm.until should work like "find"
  • Bugzilla 3185: osx is not a directory (complains cannot read std/c/osx/socket.d)
  • Bugzilla 3186: corrections for http://www.digitalmars.com/d/2.0/dmd-osx.html
  • Bugzilla 3189: `std.conv.to` : check for a custom `to` method in classes/structs
  • Bugzilla 3192: asm in a anonymous delegate crash the compiler
  • Bugzilla 3195: `std.conv` pureness (closed with "later" advise)
  • Bugzilla 3196: Segfault(mtype.c) after almost any error involving a delegate literal
  • Bugzilla 3197: Minor fixes and additions to std.traits
  • Bugzilla 3199: sort(chain(...)) doesn't work in some cases
  • Bugzilla 3205: CTFE: $ cannot be used in lvalues
  • Bugzilla 3212: Error message says "mutable"; should say "immutable"
  • Bugzilla 3217: std.functional.binaryFunImpl doesn't support UDT with string functions , therefore neither does many std.algorithm functions
  • Bugzilla 3218: Performance of std.xml.encode must be improved
  • Bugzilla 3219: Inaccurate std.conv.to!(numeric)(numeric) error messages
  • Bugzilla 3224: std.random documentation bugs
  • Bugzilla 3229: No return or assert(0) at end of function
  • Bugzilla 3236: Postblit called but no matching destructor
  • Bugzilla 3239: std.conv.roundTo does not accept const/immutable/shared
  • Bugzilla 3240: std.numeric.findRoot only works with real
  • Bugzilla 3242: splitter does not handle input range made of a unique separator correctly
  • Bugzilla 3245: Easy bug fix available for disabled unit test code in std.encoding
  • Bugzilla 3246: ICE(init.c) using indexed array initializer on local array
  • Bugzilla 3249: sort and setIntersection on array of struct or class
  • Bugzilla 3253: DMD crashes on function pointer struct member initialization with function literal
  • Bugzilla 3255: final switch broken with -w switch
  • Bugzilla 3257: Spec is unclear describing string switch case labels
  • Bugzilla 3260: "Error: undefined identifier backend" when compiling 'write' with 'wchar'
  • Bugzilla 3264: -O causes wrong "used before set" error when using enum.
  • Bugzilla 3281: ICE(cod1.c) append returned struct to array
  • Fixed bug processing spaces in dmd's directory
  • Fixed assert failure on line 4823 in expression.c
  • Fixed OSX compile error on samples/d/dhry.d
  • std.format: fixed unlisted bug in documentation
  • std.random: uniform does not work when passed immutable data
  • std.range: fixed unlisted bug in Take.back
  • unlisted: made entropy work on const/immutable arrays
Version D 2.031 July 6, 2009

New/Changed Features

  • Renamed root directory \dmd to \dmd2
  • Use of with symbols that shadow local symbols is no longer allowed
  • Added final switch statements
  • Added case range statements
  • Implicit integral conversions that could result in loss of significant bits are no longer allowed.
  • Warning on no return expr; is now an error.
  • Bugzilla 3080: dmd should output compilation errors to stderr, not stdout
  • Bugzilla 3122: [patch] Adding support for fast and reliable build tools to the frontend
  • std.algorithm: Made std.algorithm.swap faster by having it use memcpy; added std.algorithm.group, std.algorithm.until, std.algorithm.nWayUnion, std.algorithm.largestPartialIntersectionWeighted; added additional constraints to std.algorithm.equal; changed signature of std.algorithm.topNIndex and std.algorithm.topNCopy to use an enum parameter instead of a confusing bool.
  • std.array: added array function.
  • std.conv: added Shin Fujishiro's code for printing and parsing enumerated values.
  • std.ctype: made isupper and tolower pure.
  • std.date: changed signature of benchmark to return ulong[] instead of uint[].
  • std.demangle: changed it to use the snazzy switch statement with ranged labels.
  • std.random: added randomSample
  • std.string: deprecated std.string.find and std.string.find, replaced with std.string.indexOf; deprecated std.string.rfind and std.string.irfind, replaced with std.string.lastIndexOf; added flag CaseSensitive for indexOf and lastIndexOf; removed startsWith and endsWith because std.algorithm defines them; defined std.string.byDchar.
  • std.traits: added isSomeChar, isPointer.
  • std.typetuple: replaced indexOf with indexOfType, kept the old name as an alias that will be deprecated.
  • std.utf: improved error messages.

Bugs Fixed

  • Fix dmd crash on multicore Windows.
  • Fixed unlisted bug in std.algorithm.startsWith
  • Fixed unlisted bug in std.algorithm.topN
  • Fixed unlisted bug in std.algorithm.topNIndex (empty index made it crash)
  • Fixed unlisted bug in std.algorithm.setIntersection
  • Fixed unlisted bug in std.range.retro: retro'izing a range twice must return the original range
  • Bugzilla 106: template - mixin sequence
  • Bugzilla 810: Cannot forward reference template
  • Bugzilla 852: ICE(toir.c) using local class in non-static nested function in nested static function
  • Bugzilla 1343: Various errors with static initialization of structs and arrays
  • Bugzilla 1358: ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF
  • Bugzilla 1524: ICE(constfold.c) on using "is" with strings in CTFE
  • Bugzilla 1984: Assertion failure: 'e1->type' on line 1198 in file 'constfold.c'
  • Bugzilla 2323: ICE(cgcs.c): taking address of a method of a temporary struct
  • Bugzilla 2399: ICE(cgcod.c) on casting function to delegate
  • Bugzilla 2429: std.stream.File incorrect flag parsing and sharing mode
  • Bugzilla 2432: complex alias -> mtype.c:125: virtual Type* Type::syntaxCopy(): Assertion `0' failed.
  • Bugzilla 2603: ICE(cgcs.c) on subtracting string literals
  • Bugzilla 2843: ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid
  • Bugzilla 2865: RandomCover not random
  • Bugzilla 2875: ICE(cgcod.c) setting delegate = &Struct.func
  • Bugzilla 2884: ICE: Assert: 'template.c', line 3773, 'global.errors'
  • Bugzilla 2888: [PATCH] speedup for float * 2.0
  • Bugzilla 2900: Array appending slowed drastically since integration of druntime
  • Bugzilla 2915: [Patch]: Optimize -a*-b into a*b
  • Bugzilla 2923: -O generates bad code for ?:
  • Bugzilla 2932: bad e_ehsize (36 != 52)
  • Bugzilla 2952: Segfault on exit when using array ops with arrays of doubles larger than 8 elements
  • Bugzilla 2974: Segfault(mtype.c) on auto function
  • Bugzilla 2981: Bad code generation for structs containing invariants
  • Bugzilla 2982: Assertion failure in function if() clause
  • Bugzilla 3003: Need to implicitly add () on member template function calls
  • Bugzilla 3014: ICE(template.c) instantiating template with tuple
  • Bugzilla 3016: Errors in the documentation of std.math.acos
  • Bugzilla 3026: Segfault with incomplete static array initializer
  • Bugzilla 3044: Segfault(template.c) instantiating struct tuple constructor with zero arguments.
  • Bugzilla 3071: nested func declaration parse problem
  • Bugzilla 3078: NaN reported as equal to zero
  • Bugzilla 3081: unaryFun can't be used to get element out of struct.
  • Bugzilla 3095: wc example for D2 doesn't compile
  • Bugzilla 3114: optlink failing on multicore machines
  • Bugzilla 3117: dmd crash by *1
  • Bugzilla 3121: recurrence does not generate the correct numbers
  • Bugzilla 3128: Internal error: ..\ztc\cod4.c 2737
  • Bugzilla 3130: Crashed with triple stars
Version D 2.030 May 11, 2009

New/Changed Features

  • added -vtls compiler switch
  • classic global storage now defaults to TLS (Thread Local Storage). This is a big change, see Migrating To Shared.
  • std.algorithm: added minPos. Improvements to Splitter suggested by Brad Roberts. Splitter now is bidirectional. Also Splitter has one extra trailing element if it ends with a separator. Added variadic arguments for setUnion and setIntersection. Added functions setSymmetricDifference and largestPartialIntersection. Improved BinaryHeap's interface and implementation.
  • std.array: Improvements to Appender. Now it works with string and other immutable-element arrays, and accepts ranges in put().
  • std.format: added raw specifier for reading
  • std.range: Added iota with two arguments. Added FrontTransversal and Transversal.
  • std.stdio: added File.byChunk
  • std.traits: Added isImplicitlyConvertible.
  • std.tuple: Added Tuple.opComp.
  • Folded in compiler changes by Unknown W. Brackets to support Solaris.
  • added .typeinfo to ClassInfo Bugzilla 2836: Navigate from ClassInfo to TypeInfo

Bugs Fixed

  • Fix instruction scheduler bug on Linux
  • unlisted: made std.numeric.entropy work on const/immutable arrays
  • Fixed several problems associated with thread local storage
  • Bugzilla 642: error: mixin "static this" into where it cannot be
  • Bugzilla 713: circular const definitions with module operator "." cause the compiler to segfault
  • Bugzilla 752: Assertion failure: 'e->type->ty != Ttuple' on line 4518 in file 'mtype.c'
  • Bugzilla 858: Forward reference to struct inside class crashes the compiler
  • Bugzilla 884: Segfault in recursive template
  • Bugzilla 934: Segfault taking mangleof a forward reference in a template.
  • Bugzilla 1011: illegal import declaration causes compile time segfault
  • Bugzilla 1054: regression: circular aliases cause segfaults
  • Bugzilla 1061: "asm inc [;" segfaults compiler.
  • Bugzilla 1305: Compiler hangs with templated opCmp returning templated class
  • Bugzilla 1385: Stack Overflow with huge array literal.
  • Bugzilla 1428: Segfault on template specialization with delegates and tuples
  • Bugzilla 1791: Segmentation fault with anon class in anon class and non-constant variable init
  • Bugzilla 1916: segfault on invalid string concat
  • Bugzilla 1946: Compiler crashes on attempt to implicit cast const typedef to non-const.
  • Bugzilla 2048: DMD crash on CTFE that involves assigning to member variables of void-initialized struct
  • Bugzilla 2061: wrong vtable call with multiple interface inheritance
  • Bugzilla 2215: Forward reference enum with base type within a struct causes Segmentation Fault in the compiler
  • Bugzilla 2309: Crash on a template mixing in a variadic template with an undefined template identifier
  • Bugzilla 2346: ICE when comparing typedef'd class
  • Bugzilla 2580: Documented WinMain for D2 is wrong
  • Bugzilla 2633: incorrect ModuleInfo declaration in object.di
  • Bugzilla 2695: pure functions can invoke impure function pointers
  • Bugzilla 2807: Marking a nested function as 'pure' may cause bad code generations silently accepted
  • Bugzilla 2821: struct alignment inconsistent with C for { int, long }
  • Bugzilla 2851: Segfault using C-style struct initializer with too few arguments
  • Bugzilla 2865: RandomCover not random
  • Bugzilla 2882: std.random.MersenneTwisterEngine without seed
  • Bugzilla 2890: deadlock in std.stdio
  • Bugzilla 2893: qualified types don't have an Unsigned counterpart
  • Bugzilla 2906: writef problem with formatting floating point
  • Bugzilla 2914: to!string(struct) is broken
  • Bugzilla 2920: recursive templates blow compiler stack
  • Bugzilla 2922: Egregiously bad hashing performance with strings
Version D 2.029 Apr 19, 2009

New/Changed Phobos

  • std.algorithm
    • Everything converted to ranges. Big disruption. Algorithms added.
  • std.array
    • Range primitives for arrays
    • Appender template
    • insert, replace functions
  • std.bitmanip
    • Bitfields of length 0 are defined to be always 0.
    • The read functions for bitfields are const.
  • std.contracts
    • enforce accepts const(char)[] instead of string
    • Added enforce overload that invokes a delegate on failure
    • Added assumeSorted template
    • Added structuralCast that implements, well, structural casting (incomplete).
  • std.conv
    • Rewrote conversions with constrained templates.
    • Added text() function that transforms everything into text.
  • std.date
    • Added a benchmark function that allows for simple timing measurements.
  • std.file
    • read, write, append, rename, remove, getSize, getTimes, getAttributes, isfile, isdir, chdir, mkdir, mkdirRecurse, rmdir, listdir, copy, take filename(s) by "in char[]"
    • Added function readText that reads and validates a text file
    • Added function slurp that reads a file into an array of tuples. Example:
      auto a = slurp!(int, double)("filename", "%s, %s");
      Each line in the file looks like e.g. "1, 2.3". slurp returns an array of Tuple!(int, double) with the parsed content.
  • std.format
    • Added vector parsing and printing with the specifier "%()". For example, writefln("[%(s; )]", [1, 2, 3][]) writes "[1; 2; 3]". This support is experimental and may be changed in the future.
    • Added a formattedRead function (i.e., scanf that doesn't suck). The implementation is incomplete but common cases are supported.
  • std.functional
    • Improved error messages
    • Added configurable parameter names for functions as strings
    • Added Adjoin template
  • std.getopt
    • Added support for parameterless delegates
  • std.math
    • Intrinsics std.math.yl2x and yl2xp1 added. Improves performance of std.math.log() and similar functions (and they are now pure nothrow).
  • std.mmfile
    • Minor cosmetic changes
  • std.numeric
    • Added type CustomFloat that allows defining specialized floating-point numbers (e.g. 16-bit floats, positive floats etc.)
    • Added FPTemporary as the best type to store temporary values.
    • Templatized oppositeSigns
    • Added Euclidean distance
    • Added dotProduct
    • Added cosineSimilarity
    • Added normalize
    • Added string kernel functions gapWeightedSimilarity, gapWeightedSimilarityNormalized, gapWeightedSimilarityIncremental.
  • std.outbuffer
    • Added a few missing overloads of write()
  • std.path
    • getDrive now works with all string types
    • isabs accepts in char[]
    • join accepts variadic in char[]
    • fnmatch works with in char[]
  • std.random
    • Added RandomCover that covers a given range in a random manner
    • Eliminated the old-fashioned random functions
    • Defined a default random object that simplifies calls to the random functions
    • Changed generators to obey the range interface. So now you can write:
      Random r;
foreach (n; take(100, uniform(0, 100))) { ... }
  • std.range (new file)
    • Range manipulation stuff.
  • std.regex (new file)
    • Regular expression library with wide char support, simplified interface, better speed etc.
  • std.regexp
    • Scheduled for deprecation. Use std.regex instead.
  • std.stdio
    • Major breaking changes: introduced the File struct. Now stdin, stdout, stderr are instances of the File struct.
    • Due to bugs in the compiler, the copy constructor and destructor of File are commented out. Walter will look into fixing the issues soon. File should work fine, but you need to close it manually.
    • A byRecord iteration mode makes it pretty easy to iterate structured text files.
    • writef and writefln now require a string as their first argument.
  • std.string
    • strip, stripl, stripr, startsWith, endsWith now work with any string type
  • std.typecons
    • Added constructors, assignment operator, length, toString, and slice to Tuple.
  • std.utf
    • toUTF16z accepts in char[]
  • std.variant
    • Added support for Variants that contain vectors and hashes of themselves
  • std.c.stdio
    • Added fopen64 and friends

New/Changed Features

  • Added template function literals

Bugs Fixed

  • Bugzilla 675: %a format has an out-by-1 bug for denormals
  • Bugzilla 2199: Segfault using array operation in function call
  • Bugzilla 2203: typeof(class.template.foo) crashes compiler
  • Bugzilla 2577: DMD crashes on foreach of undefined identifier
  • Bugzilla 2808: 'nothrow' nested functions cannot be parsed
  • Bugzilla 2812: sqrt(2.0) is about -2.7341e-53
Version D 2.028 Apr 7, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 1586: DMD and GDC segfaults on incomplete code segment
  • Bugzilla 2064: Segfault with mixin(for/foreach) with empty loop body
  • Bugzilla 2812: sqrt(2.0) is about -2.7341e-53
  • Bugzilla 2804: Impure nested functions should be legal inside pure functions
Version D 2.027 Mar 31, 2009

New/Changed Features

  • Most functions in std.math are now pure nothrow. Improved speed of std.math.hypot.
  • Added response files for Linux and OSX
  • Added alias this
  • Bugzilla 2746: Make float.init signalling NaN by default
  • On Windows, if there are multiple source files on the command line they are now read with a background thread. This may speed up compilation.
  • Folded in patches for LDC compatibility from Tomas Lindquist Olsen
  • Removed etc.gamma from the library.

Bugs Fixed

  • std.math.hypot is wrong for subnormal arguments
  • Fix bug where / wasn't recognized as a path separator on Windows.
  • Bugzilla 920: Fix one more out of date reference to 'auto' rather than 'scope'
  • Bugzilla 1645: can override base class' const method with non-const method
  • Bugzilla 2319: "Win32 Exception" not very useful
  • Bugzilla 2336: link to nonexistent std_array.html
  • Bugzilla 2570: Patch for some mistakes in Ddoc comments
  • Bugzilla 2574: std.c.stdio doesn't compile: va_list not defined!
  • Bugzilla 2591: custom allocator new argument should be size_t instead of uint
  • Bugzilla 2595: template ctors crash compiler
  • Bugzilla 2596: Variadic constructors don't compile
  • Bugzilla 2626: template function not working against template struct instantiated with default arguments
  • Bugzilla 2674: Copy postblit constructor this(this) not called for members
  • Bugzilla 2689: seek behaves incorrectly on MAC OSX
  • Bugzilla 2692: alignment of double on x86 linux is incorrect
  • Bugzilla 2700: typeof tests stops compilation abruptly
  • Bugzilla 2705: Response file size cannot exceed 64kb
  • Bugzilla 2711: -H produces bad headers files if function defintion is templated and have auto return value
  • Bugzilla 2722: ICE with variadic template parameters
  • Bugzilla 2723: ICE with variadic template parameters, different case
  • Bugzilla 2724: Persistent segfaults in templated code
  • Bugzilla 2725: Pattern matching in static if not working with variadic arguments
  • Bugzilla 2727: std.date Cyclic dependency
  • Bugzilla 2728: Bogus Error message on const ref return
  • Bugzilla 2729: hash_t undocumented and unnecessary
  • Bugzilla 2730: Restriction on op= can be lifted
  • Bugzilla 2731: Errors in associative array example
  • Bugzilla 2739: _argptr is invalid for functions nested in class methods
  • Bugzilla 2743: dumpobj gives "buss error" on Tiger
  • Bugzilla 2744: wrong init tocbuffer of forstatement
  • Bugzilla 2745: missing token tochars in lexer.c
  • Bugzilla 2747: improper toCBuffer of funcexp
  • Bugzilla 2750: Optimize slice copy with size known at compile time
  • Bugzilla 2751: incorrect scope storage class vardeclaration tocbuffer
  • Bugzilla 2752: std.xml does not encode CData correctly
  • Bugzilla 2754: The error message regarding implicit conversion to shared doesn't mention shared in the message.
  • Bugzilla 2755: ICE on invalid ref returns in linked objects: Assertion failure: 'type' on line 6566 in file 'expression.c'. No ICE or error if invalid code is local to the file.
  • Bugzilla 2756: Bad code generation for pure nothrow math functions
  • Bugzilla 2761: Unreachable statement warning in std.string
  • Bugzilla 2763: std.mangle.demangle not translating 'ya'
  • Bugzilla 2766: DMD hangs with 0%cpu
  • Bugzilla 2767: DMD incorrectly mangles NTFS stream names
  • Bugzilla 2772: lib can't open response file
Version D 2.026 Mar 3, 2009

New/Changed Features

  • Escape string literals deprecated, see Bugzilla 2658
  • Tripled speed of exp, expm1, and exp2. std.math is now less dependent on the C standard library.
  • Added nested structs.
  • Added buildable dmd source.
  • Many changes to std.math for speed, accuracy, and Tango compatibility:
    • Improved accuracy of exp, expm1, exp2, sinh, cosh, tanh on Mac OSX, and tripled speed on all platforms.
    • Now using IEEE754-2008 camelCase names for isNaN, isFinite, isNormal, isSubnormal, isInfinity. Aliases for the old names have been retained.
    • The non-functional nan(char[]) is replaced with NaN, getNaNpayload.

Bugs Fixed

  • Bugzilla 1603: String literals bind to pointer types
  • Bugzilla 1629: Link error: Previous Definition Different: blablah__initZ
  • Bugzilla 1662: Falls back to libphobos if -debuglib isn't used when -g is
  • Bugzilla 1681: cast(real) ulong.max == 0
  • Bugzilla 2416: Slice of typedef'ed array should preserve the typedef'ed type
  • Bugzilla 2597: auto return doesn't work for a variety of cases
  • Bugzilla 2612: immutable not accepted wherever invariant is
  • Bugzilla 2619: Locally-instantiated structs are not instantiated locally
  • Bugzilla 2621: ref binds to rvalues of user-defined types
  • Bugzilla 2622: ref returns not allowed in complex template
  • Bugzilla 2623: Function type drops ref spec
  • Bugzilla 2670: std.file.read() should read files of 0 length
  • Bugzilla 2673: Static constructors sometimes do not run when compiling with -lib
  • Bugzilla 2675: cannot foreach structs with copy constructor
  • Bugzilla 2676: alias parameters not matched in concept if clause
  • Bugzilla 2677: Alias type parameters not visible in concept-if clauses
  • Bugzilla 2678: for loops are already assumed to terminate
  • Bugzilla 2679: Spurious "warning - " messages and erratic behaviour with is(typeof({void function}()))
  • Bugzilla 2684: Associative arrays have wrong opIndex signatures
  • Bugzilla 2690: DMD aborts with MALLOC_CHECK_ set
Version D 2.025 Feb 14, 2009

New/Changed Features

  • Added Mac OSX support.
  • Separated bin and lib directories into windows, linux, and osx.
  • No longer need to download dmc to use the windows version.
  • Use version(OSX) for Mac OSX. Although version(darwin) is also supported for the time being, it is deprecated.

Bugs Fixed

  • Bugzilla 2448: template return by reference causes seg fault
Version D 2.023 Jan 2, 2009

New/Changed Features

  • Improved speed of long division.
  • Optimizer now takes advantage of immutable and pure.
  • Added predefined version D_Ddoc which is predefined when -D switch is thrown.
  • the type of a string literal is now invariant(char)[] rather than invariant(char)[length_of_string]. It is still implicitly convertible to the latter. This is intended to reduce template instantiation bloat.
  • Undid fix for Bugzilla 2500, as the fix was arguably worse than the bug.

Bugs Fixed

  • Bugzilla 1078: Frontend uses of 'auto' where 'scope' should be used
  • Bugzilla 2517: DDoc omits abstract on classes
  • Bugzilla 2518: scope(success) not execuate and RAII variable destructor is not called
  • Bugzilla 2519: Segfault when >> used in an invalid slice
  • Bugzilla 2527: Alias Template Params Are Always Same Type As First Instantiation (according to typeof(x).stringof)
  • Bugzilla 2531: DDoc not generated correctly for struct methods inside static if
  • Bugzilla 2533: compiler falls with "assertion failed" message on wrong code
  • Bugzilla 2534: dmd.conf is wrong
  • Bugzilla 2537: compiler crashes on this code:
  • Bugzilla 2541: cannot use aliased type for decl of foreach variable
  • Bugzilla 2542: array casts behave differently at compile and runtime
Version D 2.022 Dec 11, 2008

New/Changed Features

  • Changed IUnknown to use the extern(System) interface rather that extern(Windows).
  • Pure functions now get semantically checked.
  • Nothrow functions now get semantically checked.
  • shared is now a type constructor.

Bugs Fixed

  • Bugzilla 1518: Crash using 'scope', 'with' and undefined 'RegExp'
  • Bugzilla 1649: Variant coercion fails with delegates
  • Bugzilla 1685: Array index is evaluated twice
  • Bugzilla 1933: Delimited string constants can cause segfault
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2041: Spec implies relationship between interfaces and COM objects
  • Bugzilla 2105: added patch
  • Bugzilla 2441: header file generation translates enum to manifest
  • Bugzilla 2468: result type of AndAndExp and OrOrExp deduced incorrectly
  • Bugzilla 2489: import in struct causes assertion failure
  • Bugzilla 2490: extern(C++) can not handle structs as return types
  • Bugzilla 2491: druntime GC wrongly frees data pointed to by TLS.
  • Bugzilla 2492: ICE building on Linux with -lib option
  • Bugzilla 2499: Template alias default value cannot be template instantiation
  • Bugzilla 2500: template struct methods are left unresolved if imported from multiple modules
  • Bugzilla 2501: member function marked as final override ignores override requirements
  • Bugzilla 2503: Error 42: Symbol Undefined _D3std7process6systemFAyaZi
  • Bugzilla 2506: Can't initialize const member in ctor if it is accessed via this.member syntax
  • Incorporated some of the patches from Bugzilla 1752
  • extern __thread now works on Linux.
Version D 2.021 Nov 25, 2008

New/Changed Features

  • Added -safe switch and module(system) Identifier; syntax.
  • Added range support to foreach statement.
  • scope parameter storage class means the parameter will not 'escape' the scope of the function invocation. Using this for delegate parameters will prevent some closure allocations by the calling function.
  • The lazy storage class now implies scope so that lazy arguments won't trigger a heap allocated closure.
  • The 'this' parameter to struct member functions is now a reference type, rather than a pointer. This breaks existing code.
  • More changes to druntime:
    from | to
    OutOfMemoryException | OutOfMemoryError
    SwitchException | SwitchError
    HiddenFuncException | HiddenFuncError
    ArrayBoundsException | RangeError
    AssertException | AssertError
    FinalizeException | FinalizeError
    onArrayBoundsError | onRangeError
    stdc.* | core.stdc.*
    sys.* | core.sys.*
  • Added core.runtime.loadLibrary() as an experimental feature for loading dynamic libraries (Win32 only at the moment).
  • Added core.runtime.unloadLibrary() as an experimental feature for unloading dynamic libraries previously loaded by loadLibrary().
  • core.thread.sleep() accepts a long integer specifying the sleep interval in 100 nanosecond intervals (the previous release notes said this was a float, IIRC).
  • It is no longer necessary to link in druntime separately, it is inserted into libphobos2.a.

Bugs Fixed

  • Bugzilla 313: Fully qualified names bypass private imports
  • Bugzilla 920: SPEC: Auto classes referenced where scope should be used
  • Bugzilla 929: Resizing array of associative arrays (uint[char[]][]) causes infinite loop / hang
  • Bugzilla 1372: Compiler accepts pragma(msg,)
  • Bugzilla 1610: Enum.stringof is int, not the name of the enum
  • Bugzilla 1663: pragma(lib, "") don't work on linux
  • Bugzilla 1797: Documentation comments - ///
  • Bugzilla 2428: Accessing item in enum'd array produced compiler error
  • Bugzilla 2429: std.stream.File incorrect flag parsing and sharing mode
  • Bugzilla 2431: Internal error: ../ztc/cgcod.c 1031 when using -O
  • Bugzilla 2470: Cannot build libraries from other libraries
  • unittest functions now always use D linkage
Version D 2.020 Oct 20, 2008

New/Changed Features

  • Improved performance of AAs by rebalancing trees when rehashing.
  • immutable now is implemented.
  • Bugzilla 2344: Two wrong lookups for array functions
  • Bugzilla 2345: Return by reference should be allowed
  • Posix is now a predefined identifier when compiling under Linux
  • Based on Sean Kelly's hard work, Phobos has been split into two libraries, druntime.lib and phobos.lib. This will enable better integration with Tango. The user source code changes are:
    from | to
    bit | bool
    _d_OutOfMemory() | onOutOfMemoryError()
    import std.asserterror; | import core.exception;
    import std.hiddenfunc; | import core.exception;
    import std.switcherr; | import core.exception;
    import std.array; | import core.exception;
    import std.outofmemory; | import core.exception;
    import std.gc; | import core.memory;
    import std.thread; | import core.thread;
    SwitchError | SwitchException
    AssertError | AssertException
    HiddenFuncError | HiddenFuncException
    ArrayBoundsError | ArrayBoundsException
    std.gc.fullCollect() | GC.collect()
    std.gc.*() | memory.gc_*()
    _moduleUnitTests() | import runtime; runModuleUnitTests()
    printf | add import std.c.stdio;
    Changes to thread:
    • The thread handle isn't exposed to the user. This can always be obtained using the appropriate OS calls from within the thread.
    • There is no druntime equivalent for Thread.pause() and Thread.resume(). The closest is thread_suspendAll() and thread_resumeAll()--extern (C) calls meant for use by the GC.
    • Thread.wait() is renamed to Thread.join().
    • Sleep functionality is available as Thread.sleep(double), where the parameter represents the number of seconds to sleep (fractional values accepted, obviously).
    This is a big change, and expect some problems for a release or two with this.

Bugs Fixed

  • Bugzilla 1229: Linker fills disk
  • Bugzilla 2332: Initializing const or invariant hashes croaks
  • Bugzilla 2333: Hash initializer does not work
  • Bugzilla 2336: link to nonexistent std_array.html
  • Bugzilla 2340: Template properties don't work
  • Bugzilla 2341: Double destruction without intervening copy
  • Bugzilla 2362: Confusing description of 'aliasing of invariant with mutable'?
  • Bugzilla 2363: Spurious () required after function name when used with array in prefix form
  • Bugzilla 2366: Const member function syntax is missing
  • Bugzilla 2368: Calling a function with an address of another function, then calling a returned object is rejected
  • Bugzilla 2373: freebsd select does not accept values > 999,999
  • Bugzilla 2376: CTFE fails on array literal of array literals of chars
  • Bugzilla 2380: static struct initializer accepted as non static initializer is not documented
  • Bugzilla 2383: default arguments can implicitly access private global variables that are not visible at call site
  • Bugzilla 2385: spec says all structs are returned via hidden pointer on linux, but it uses registers
  • Bugzilla 2390: Missing warning on conversion from int to char
Version D 2.019 Sep 2, 2008

New/Changed Features

  • Added struct constructors.
  • Special member functions _ctor, _dtor, etc., now have two leading _ in order to not conflict with the user identifier space.

Bugs Fixed

  • Bugzilla 1322: foreach bypasses invariant
  • Bugzilla 1615: inout is allowed in foreach of string literal
  • Bugzilla 1627: ICE with a method called _ctor
  • Bugzilla 1633: Nonsensical "C style cast illegal" message with !is
  • Bugzilla 1771: dmd fails to execute on linux
  • Bugzilla 1773: excessively long integer literal
  • Bugzilla 1785: Mixing in an incorrect array literal causes infinite loop.
  • Bugzilla 2176: Assertion failure: 'sz == es2->sz' on line 1339 in file 'constfold.c' (concatenating strings of different types)
  • Bugzilla 2183: Bad formatting in std.c.stdlib
  • Bugzilla 2190: toHash documentation is deprecated [D2.0]
  • Bugzilla 2232: DMD generates invalid code when an object file is compiled -inline
  • Bugzilla 2241: DMD abort
  • Bugzilla 2243: const bool = is(function literal), badly miscast
  • Bugzilla 2262: -inline breaks -lib library
  • Bugzilla 2286: movmskpd compiled incorrectly
  • Bugzilla 2287: std.conv should accept structs defining toString
  • Bugzilla 2289: Stack overflow on very large BigInt to string.
  • Bugzilla 2308: CTFE crash on foreach over nonexistent variable
  • Bugzilla 2311: Static destructors in templates are never run
  • Bugzilla 2314: Crash on anonymous class variable instantiation
  • Bugzilla 2316: std.file docs are out of date
  • Bugzilla 2317: asm offsetof generates: Internal error: ../ztc/cod3.c 2651
Version D 2.018 Aug 7, 2008

New/Changed Features

  • Now supports array operations.

Bugs Fixed

  • Added hash to generated module names when building libs to reduce collisions
  • Bugzilla 1622: parameters to TypeInfo_Struct.compare seem to be switched around.
  • Bugzilla 1644: Template instantiation should automatically cast to const to make const-ness irrelevant when argument is const anyways
  • Bugzilla 2216: bad code generation for static arrays of zero length static arrays
  • Bugzilla 2223: Typo in error message
  • Bugzilla 2231: missing bigint document
  • Bugzilla 2242: linux system calls are canceled by GC
  • Bugzilla 2247: bad header file generated for if (auto o = ...) {}
  • Bugzilla 2248: .di should be a supported file extension
  • Bugzilla 2250: Update of user32.lib and kernel32.lib
  • Bugzilla 2254: Size of executable almost triples
  • Bugzilla 2258: Docs -> Inline Assembler -> Operand Types -> qword missing
  • Bugzilla 2259: Assertion failure: '0' on line 122 in file 'statement.c'
  • Bugzilla 2266: opEquals documentation still says it returns int
  • Bugzilla 2269: D BUG: cosine of complex
  • Bugzilla 2272: synchronized attribute documentation
  • Bugzilla 2273: Whitespace is not inserted after commas
Version D 2.017 Jul 11, 2008

New/Changed Features

Bugs Fixed

  • Bugzilla 2207: overload resolution fails with deprecation
  • Bugzilla 2208: Deprecated function declarations cannot use deprecated types
  • Bugzilla 2209: Typo in doc for offsetof
  • Bugzilla 2212: phobos itself should be able to be compiled with '-w' switch
  • Bugzilla 2264: typo in documentation regarding atof.
Version D 2.016 Jul 8, 2008

New/Changed Features

  • re-implemented internal.monitor in D. Rationalized internal.object
  • Bugzilla 288: changed return type of opEquals from int to bool. This necessitates doing a grep for opEquals and changing all the return values.
  • Added .__vptr and .__monitor properties for class objects for use in the internal runtime library.
  • Made rdmd's source available through svn, see http://dsource.org/projects/phobos/browser/trunk/tools/rdmd.d
  • Simplified std.algorithm by fusing together higher-order functions taking an alias and their counterparts taking a string
  • Added module std.array containing array operations: insert, erase, and replace
  • Changed the enforce's implementation to generate smaller code per call
  • Changed std.functional.binaryFun to work with strings and function aliases alike
  • In std.getopt, added optChar, assignChar, and endOfOptions, per popular demand :o|
  • In std.math, replaced a bunch of consts with enums
  • In std.numeric, added Don Clugston as author and operated minor documentation fixes
  • Improved std.stdio.chunks to take an iteration tally in addition to the chunk

Bugs Fixed

  • D.announce/12322: mixin regression
  • Bugzilla 203: std.format.doFormat() pads width incorrectly on Unicode strings
  • Bugzilla 211: Linking error with alias mixin params and anonymous methods
  • Bugzilla 224: Incorrect warning "no return at end of function"
  • Bugzilla 252: -w and switch returns = bogus "no return at end of function" warning
  • Bugzilla 253: Invalid <dl> tag generated by Ddoc
  • Bugzilla 294: DDoc: Function templates get double and incomplete documentation
  • Bugzilla 398: No way to abort compilation in a doubly recursive mixin
  • Bugzilla 423: dmd ignores empty commandline arguments
  • Bugzilla 515: Spec incorrect in where .offsetof can be applied
  • Bugzilla 520: Invariants allowed to call public functions
  • Bugzilla 542: Function parameter of a deprecated type (other than a class) is not caught
  • Bugzilla 543: Function return of a deprecated type is not caught
  • Bugzilla 544: Variable declared of a deprecated type (other than a class) is not caught
  • Bugzilla 545: Attempt to access a static built-in property of a deprecated struct, union, enum or typedef is not caught
  • Bugzilla 547: Accessing a deprecated member variable through an explicit object reference is not caught
  • Bugzilla 548: Accessing a value of a deprecated enum is not caught
  • Bugzilla 566: Adding non-static members and functions to classes using a template doesn't error
  • Bugzilla 570: Bogus recursive mixin error
  • Bugzilla 571: class instance member template returns strange value
  • Bugzilla 572: parse error when using template instantiation with typeof
  • Bugzilla 581: Error message w/o line number in dot-instantiated template
  • Bugzilla 617: IFTI doesn't use normal promotion rules for non-template parameters
  • Bugzilla 870: contradictory error messages for templates
  • Bugzilla 951: Missing line number: no constructor provided for a class derived from a class with no default constructor
  • Bugzilla 1097: Missing line number: casting array to array of different element size
  • Bugzilla 1158: Missing line number: invalid mixin outside function scope
  • Bugzilla 1176: Error missing file and line number
  • Bugzilla 1187: Segfault with syntax error in two-level mixin.
  • Bugzilla 1194: fcmov* emmits incorrect code
  • Bugzilla 1207: Documentation on destructors is confusing
  • Bugzilla 1341: typeof(int) should probably be legal
  • Bugzilla 1601: shr and shl error message is missing line numbers
  • Bugzilla 1612: No file/line number for using an undefined label in inline assembly
  • Bugzilla 1912: Error without line number (Tuple, invalid value argument)
  • Bugzilla 1936: Error with no line number (array dimension overflow)
  • Bugzilla 2076: asm: offset has wrong docs and error without line number
  • Bugzilla 2161: Modify compiler to pass array TypeInfo to _adEq and _adCmp instead of element TypeInfo
  • Bugzilla 2178: 3 errors without line number: typeof
  • Bugzilla 2188: man-or-boy test fails with access violation
  • Fixed bugs in std.file.rename and std.file.remove on Linux
  • Fixed documentation in std.typecons
Version D 2.015 Jun 17, 2008

New/Changed Features

  • Template alias arguments can now be literals.
  • Function templates can now deduce the return type if they are declared with auto.
  • Non-lvalues are no longer matched to ref and out parameters when overloading.
  • Relaxed hidden hijacking detection when hidden function is disjoint from overloading with any other virtual function in the hierarchy.
  • Added version identifier D_PIC when -fPIC switch is used.
  • Added Constraints to templates.

Bugs Fixed

  • Bugzilla 1383: Implicit Function Instantiation with typesafe-variadic of delegates doesn't work
  • Bugzilla 1559: version statement makes code outside of it disappear
  • Bugzilla 1675: "Identifier too long" error with OMF object files
  • Bugzilla 1947: ICE (Assertion failure: '0' on statement.c:123) with null mixin
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2098: Outdated docs
  • Bugzilla 2099: Text and Sample Code Disagree (non-static local invariant declaration)
  • Bugzilla 2112: the type of undefined variable incorrectly assumed to be int
  • Bugzilla 2118: Inconsistent use of string vs invariant(char[]) in doc
  • Bugzilla 2123: Anonymous class crashes
  • Bugzilla 2129: foreach won't work with invariant limits
  • Bugzilla 2132: CTFE: can't evaluate ~= at compile time, D2 only.
  • Bugzilla 2133: anonymous enum without {} doesn't work as asm value
  • Bugzilla 2136: typeof(super(...)) counted as a constructor call
  • Bugzilla 2140: static if as final statement with no code causes containing code to be skipped
  • Bugzilla 2143: Mixed-in identifier is not recognized by static if
  • Bugzilla 2144: 'is' is defined to be the same as '==' for non-class and non-array types, but does not call opEquals
  • Bugzilla 2145: Phobos buildsystem unable to build html
  • Bugzilla 2146: Multiple execution of 'static this' defined in template
  • Bugzilla 2149: Auto variables loose the keyword "auto" in di files generated with -H option.
Version D 2.014 May 16, 2008

New/Changed Features

  • Added -man switch to browse manual.
  • Added -lib switch to generate library files. Also causes multiple object files to be generated from one source module.
  • When generating an executable file, only one object file is now generated containing all the modules that were compiled, rather than one object file per module.
  • Rewrote the rdmd utility to properly track dependencies and command-line compiler options (currently only working under Linux).
  • Changed the Phobos makefile linux.mak to take advantage of the new -lib feature. Improved full build speed by 3x.
  • std.algorithm: Changed the map() function so that it deduces the return type. Also map can be now curried.
  • std.contracts: Added file and line information to enforce. Added errnoEnforce that formats the error message according to errno. Added corresponding ErrnoException class.
  • std.conv: Made std.to curryable. Changed std.to to throw exception when object-to-object cast fails. Eliminated some superfluous printfs.
  • std.encoding: Added new functions encodedLength(dchar) and encode(dchar, ref E[])
  • std.encoding: Got rid of types Utf8, Utf16, Utf32, Ascii, Latin1, Windows1252. Introduced types AsciiChar, AsciiString, Latin1Char, Latin1String, Windows1252Char, Windows1252String.
  • std.encoding: For now commented out std.encoding.to.
  • std.file: Changed Boolean function signatures (e.g. exists) to return bool instead of int. Got rid of some gotos. Added the readText, lastModified, mkdirRecurse, and rmdirRecurse functions.
  • std.functional: Improved compose so it accepts an unbounded number of functions. Added the pipe function.
  • std.getopt: Added new option stopOnFirstNonOption. Also automatically expand dubious option groups with embedded spaces in them (useful for shebang scripts)
  • std.math: improved integral powers
  • std.md5: Improved signature of sum so it takes multiple arrays. Added getDigestString.
  • std.path: changed signatures of test functions from bool to int. Implemented rel2abs for Windows. Improved join so that it accepts multiple paths. Got rid of some gotos with the help of scope statements.
  • std.process: added getenv and setenv. Improved system() so it returns the exit code correctly on Linux.
  • std.random: added the dice function - a handy (possibly biased) dice.
  • std.typecons: Finalized and documented the stupendous Rebindable template.
  • std.utf: added the codeLength function. Got rid of some gotos.

Bugs Fixed

  • std.format: Fixed unlisted bug in raw write for arrays
  • std.getopt: Fixed unlisted bug in dealing with one-letter options with bundling disabled
  • Bugzilla 2014: fopen fails on large files.
  • Bugzilla 2031: Documentation: template value parameters
  • Bugzilla 2032: Documentation for creating a class on the stack is unintuitive
  • Bugzilla 2037: Article on hijacking is outdated
  • Bugzilla 2038: Remove hello2.html from samples directory
  • Bugzilla 2039: -ignore switch is missing from compiler docs
  • Bugzilla 2054: Const system broken on struct assignment.
  • Bugzilla 2055: (ICE) Compiler crash on struct initializer with too many elements
  • Bugzilla 2056: Const system does not allow certain safe casts/conversions involving deep composite types
  • Bugzilla 2058: Describe hidden value passed to class member functions
  • Bugzilla 2063: std.xml access violation for nested, closed tags
  • Bugzilla 2065: Return value of std.file.exists() is inverted.
  • Bugzilla 2067: call from anonymous class makes access violation.
  • Bugzilla 2071: spec doesn't mention pointer arithmetic with two pointer operands
  • Bugzilla 2072: std.typecons documentation anomaly.
  • Bugzilla 2074: Variant arithmetic operations fail. For now the fix is to comment out all right-hand side operators. Suggestions for a better fix are welcome.
  • Bugzilla 2075: Spec does not specify how array literals are stored.
  • Bugzilla 2084: operator ?: does not compute the tightest type
  • Bugzilla 2086: Describe relationship between string and char[] more explicitly
  • Bugzilla 2089: Issues with CTFE and tuple indexes
  • Bugzilla 2090: Cannot alias a tuple member which is a template instance
  • Bugzilla 2100: Assertion failure: '0' on line 4842 in file 'expression.c'
  • Bugzilla 2109: asm {lea EAX, [0*0+EAX]; } rejected.
Version D 2.013 Apr 22, 2008

New/Changed Features

  • Added -ignore switch to ignore unsupported pragmas.
  • Unsupported pragmas now printed out with -v switch.
  • Added opDot, which is experimental only.
  • SwitchStatements can now accept runtime initialized const and invariant case statements.
  • Changed __FILE__ and __LINE__ so they work as parameter default initializers.
  • Incorporated Benjamin Shropshire's doc changes
  • Hidden methods now get a compile time warning rather than a runtime one.
  • Html source files are now deprecated.
  • Added pure and nothrow function attributes, although their semantics are not implemented.
  • Deprecated VolatileStatement; use SynchronizedStatement instead.
  • Added __thread storage class for thread local storage. This is for testing purposes only to check out the machinery in the back end. The front end design of this will change.
  • obj2asm and dumpobj now better handle special ELF fixup records.
  • Added partial ordering rules to disambiguate function overloading.
  • std.perf: Bill Baxter cleaned it up.
  • std.xml.Document constructor now creates whole DOM tree.
  • Added std.encoding.

Bugs Fixed

  • D/69085: const/invariant bug?
  • Bugzilla 1712: vtbl[0] for interface not set to corresponding Interface*
  • Bugzilla 1723: __traits(getVirtualFunctions) on a non-function fails badly
  • Bugzilla 1741: crash on associative array with static array as index type
  • Bugzilla 1905: foreach docs inconsistency
  • Bugzilla 1906: foreach cannot use index with large arrays
  • Bugzilla 1925
  • Bugzilla 1935: The std.recls samples in the DMD .zip are obsolete.
  • Bugzilla 1967: getDirName does not seem to use altsep on windows
  • Bugzilla 1978: Wrong vtable call
  • Bugzilla 1991: Dmd hangs
  • Bugzilla 2016: 'invariant' TypeSpecialization is missing
  • Bugzilla 2019: Appending a one-element array literal doesn't work
Version D 2.012 Mar 6, 2008

New/Changed Features

  • Added predefined version(unittest). See Bugzilla 458
  • Removed std.math2
  • Added compile time error for comparing class types against null.
  • Added struct destructors and postblits.
  • std.algorithm: Made some imports conditional for the Unittest version; fixed doc typo; made min and max always return the tightest type and work with mixes of signed and unsigned; changed enum value names to obey lowercase convention; changed OrderStrategy to SwapStrategy as it's not just for ordering (e.g. see eliminate).
  • std.bitmanip: simplified code generated for bitfields and improved error message.
  • std.format: ate dogfood: used bitfields internally.
  • std.functional: fixed binaryfun to work with constant-size arrays; added compose.
  • std.random: made unpredictableSeed return different numbers every call (except for rarely-encountered MT scenarios); added private variable name that will take experts millenia to figure out; changed the boundaries syntax from two separate characters '[', '(' to one string "[(" throughout.
  • std.traits: added mostNegative, mostly to assuage for the unpardonable mistake of inheriting C++'s unpardonable mistake of defining "min" to mean very different things for floating-point types and integral types.
  • std.typecons: added undocumented Rebindable in preparation for opImplicitCast.
  • std.math:
    • Support for different CPU IEEE 'real' formats: 64-bit, 80-bit and 128-bit (quadruple) reals, both BigEndian and LittleEndian; partial support for non-IEEE 'doubledouble' reals.
    • Added implementation of nextafter Bugzilla 1722 and scalb for DMD-Windows.
    • Added nextUp(), nextDown()
    • Bugzilla 1881: feqrel nonsensical for non-real arguments.
    • internal functions isPosZero(), isNegZero() removed in favour of the more generally useful isIdentical().
    • asm versions of functions which were not implemented by DMD Windows: scalb, lrint.
    • added creal expi(real y) which is useful for simultaneous calculation of sin + cos.

Bugs Fixed

  • std.contracts: fixed unlisted bug in pointsTo.
  • std.conv: fixed bug related to number-to-number conversion (T.min hits again).
  • Fixed dwarf bug with DT_AT_upper_bound
  • Bugzilla 756: IFTI for tuples only works if tuple parameter is last
  • Bugzilla 1454: IFTI cant deduce parameter if alias argument used
  • Bugzilla 1661: Not possible to specialize on template with integer parameter
  • Bugzilla 1800: Compiler crash on enums nested in structs
  • Bugzilla 1801: Const structs should be assignable to non-const variables unless they contain references
  • Bugzilla 1806: "const" makes typesafe variadic arguments not work properly.
  • Bugzilla 1809: template.c:2600
  • Bugzilla 1810: MmFile anonymous mapping does not work under win32
  • Bugzilla 1819: spurious warning about missing return statement after synchronized
  • Bugzilla 1821: ICE when using __traits isSame on const/invariant variables
  • Bugzilla 1823: Implicit conversion to const on associative array
  • Bugzilla 1828: Several Thread Issues
  • Bugzilla 1833: std.c.windows.windows should use enums for constants, or be more selective about use of extern(Windows)
  • Bugzilla 1836: Inline assembler can't use enum values as parameters.
  • Bugzilla 1837: Make dmd stop flooding the console: prints content of passed parameter file
  • Bugzilla 1843: Bogus unreachable statement on forward referenced struct, lacks line number
  • Bugzilla 1850: The compiler accepts lower case asm registers.
  • Bugzilla 1851: missing opCall? when cast away const struct
  • Bugzilla 1852: you get opCall missing when cast to a struct(diagnostic)
  • Bugzilla 1853: opCmp documentation really needs some examples
  • Bugzilla 1854: bug in new flow analysis (warnings on valid code)
  • Bugzilla 1857: Runtime segfault while profileing - jump to invalid code address
  • Bugzilla 1862: asm: [ESI+1*EAX] should be a legal addr mode
  • Bugzilla 1865: Escape sequences are flawed.
  • Bugzilla 1867: lazy adds spurious const qualifier
  • Bugzilla 1871: DMD debug messages printed
  • Bugzilla 1873: structs with at least one immutable member are completely immutable
  • Bugzilla 1874: __traits(allMembers, T) fails to list methods which only have non-mutating overloads
  • Bugzilla 1876: inside a non-static class method, should "&( f)" be same as "&(this.f)" ?
  • Bugzilla 1877: Errors in the documentation of std.math.atan2
  • Bugzilla 1882: Internal error: ..\ztc\cod1.c 2529
  • Bugzilla 1883: templates instantiated as real gives incorrect values
  • Bugzilla 1884: manifest constants for strings
  • Bugzilla 1885: Syntax error for object identity test between invariant/mutable references
  • Bugzilla 1887: compiler freeze on array of dyn. arrays with empty first initializer
Version D 2.011 Feb 18, 2008

New/Changed Features

  • std.typecons: fixed code bloat issue; added Tuple.toString; added function tuple(); fixed unlisted bug in enumValuesImpl.
  • std.process: added function shell().
  • std.math: minor change in approxEqual.
  • std.contracts: added functions pointsTo()
  • std.numeric: minor unittest fixes.
  • std.bitmanip: fixed code bloat issue, reintroduced FloatRep and DoubleRep.
  • std.conv: minor simplification of implementation.
  • std.regexp: added reference to ECMA standard in the documentation.
  • std.getopt: changed return type from bool to void, error is signaled by use of exceptions.
  • std.functional: added unaryFun, binaryFun, adjoin.
  • std.string: updated documentation, changed code to compile with warnings enabled.
  • std.traits: changed FieldTypeTuple; added RepresentationTypeTuple, hasAliasing; fixed bug 1826; added call to flush() from within write; fixed unlisted bug in lines().
  • std.algorithm: added map, reduce, filter, inPlace, move, swap, overwriteAdjacent, find, findRange, findBoyerMoore, findAdjacent, findAmong, findAmongSorted, canFind, canFindAmong, canFindAmongSorted, count, equal, overlap, min, max, mismatch, EditOp, none, substitute, insert, remove, levenshteinDistance, levenshteinDistanceAndPath, copy, copyIf, iterSwap, swapRanges, reverse, rotate, SwapStrategy, Unstable, Semistable, Stable, eliminate, partition, nthElement, sort, schwartzSort, partialSort, isSorted, makeIndex, schwartzMakeIndex, lowerBound, upperBound, equalRange, canFindSorted.
  • std.thread: fixed so it compiles with warnings enabled.
  • std.file: made getSize() faster under Linux.
  • std.random: fixed so it compiles with warnings enabled; improved function uniform so it deduces type generated from its arguments.
  • std.format: added fixes to make formatting work with const data.
  • std.path: minor documentation changes.
  • Added std.xml
  • Added std.complex
  • Added std.iterator
  • Added std.c.linux.tipc
  • Added std.c.linux.termios
  • Added nothrow keyword
  • Re-enabled auto interfaces.
  • Now allow static arrays to be lvalues.
  • Now allows implicit casting of null to/from const/invariant.
  • Now allows implicit casting of StructLiterals if each of its arguments can be implicitly cast.
  • Now allows implicit casting of structs to/from const/invariant if each of its fields can be.
  • Added pragma startaddress.
  • .tupleof can now access private fields of a struct/class
  • Enhancement Bugzilla 493: Partial IFTI does not work

Bugs Fixed

  • Fixed D/66406 Remaining const niggles #1 - Custom POD types
  • Fixed display of ddoc template parameters that were aliased
  • Fixed bug in std.file.readln() for Windows in translated mode
  • Bugzilla 1072: CTFE: crash on for loop with blank increment
  • Bugzilla 1435: DDoc: Don't apply DDOC_PSYMBOL everywhere
  • Bugzilla 1815: foreach with interval does not increment pointers correctly
  • Bugzilla 1825: local instantiation and function nesting
  • Bugzilla 1837: Make dmd stop flooding the console: prints content of passed parameter file
  • Bugzilla 1842: Useless linker command line output during compilation on Linux
Version D 2.010 Jan 20, 2008

New/Changed Features

  • opAssign can no longer be overloaded for class objects.
  • WinMain and DllMain can now be in template mixins.
  • Added pure keyword.

Bugs Fixed

  • Bugzilla 1319: compiler crashes with functions that take const ref arguments
  • Bugzilla 1697: Internal error: ..\ztc\cgcod.c 2322 with -O
  • Bugzilla 1700: ICE attempting to modify member of const return struct
  • Bugzilla 1707: '==' in TemplateParameterList in IsExpression causes segfault
  • Bugzilla 1711: typeof with delegate literal not allowed as template parameter
  • Bugzilla 1713: foreach index with tuples and templates fails
  • Bugzilla 1718: obscure exit with error code 5
  • Bugzilla 1719: Compiler crash or unstable code generation with scoped interface instances
  • Bugzilla 1720: std.math.NotImplemented missing a space in message
  • Bugzilla 1724: Internal error: toir.c 177
  • Bugzilla 1725: std.stream.BufferedFile.create should use FileMode.OutNew
  • Bugzilla 1757: there is an fault in phobos windows api interface
  • Bugzilla 1762: Wrong name mangling for pointer args of free extern (C++) functions
  • Bugzilla 1767: rejects-valid, diagnostic
  • Bugzilla 1769: Typo on the page about exceptions
  • Bugzilla 1773: excessively long integer literal
  • Bugzilla 1779: Compiler crash when deducing more than 2 type args
  • Bugzilla 1783: DMD 1.025 asserts on code with struct, template, and alias
  • Bugzilla 1788: dmd segfaults without info
  • D.announce/11066: Re: DMD 1.025 and 2.009 releases
Version D 2.009 Jan 1, 2008

New/Changed Features

  • Redid const/invariant semantics again.
  • Extended enums to allow declaration of manifest constants.

Bugs Fixed

  • Bugzilla 1111: enum value referred to by another value of same enum is considered as enum's base type, not enum type
  • Bugzilla 1694: Zip::ArchiveMember::name format bug
  • Bugzilla 1702: ICE when identifier is undefined
  • Bugzilla 1738: Error on struct without line number
  • Bugzilla 1742: CTFE fails on some template functions
  • Bugzilla 1743: interpret.c:1421 assertion failure on CTFE code
  • Bugzilla 1744: CTFE: crash on assigning void-returning function to variable
  • Bugzilla 1745: Internal error: ..\ztc\out.c 115
  • Bugzilla 1749: std.socket not thread-safe due to strerror
  • Bugzilla 1753: String corruption in recursive CTFE functions
  • D/63456: Cannot overload on constancy of this
Version D 2.008 Nov 27, 2007

New/Changed Features

  • std.string: Made munch more general and added function chompPrefix.
  • std.variant: Added documentation for variantArray
  • std.traits: Added CommonType template, fixed isStaticArray.
  • std.bitarray: scheduled for deprecation
  • std.bitmanip: new module with the content of std.bitarray plus the bitfields, FloatRep, and DoubleRep templates
  • std.process: Made getpid visible in Linux builds
  • std.math: Made nextafter visible for all floating types. Added approxEqual template.
  • std.contracts: Added enforce signature taking an exception
  • std.conv: Made conv_error a template parameterized on the types being converted.
  • std.stdio: Cosmetic changes.
  • std.system: Cosmetic changes.
  • std.file: Fixed bug in function dirEntries.
  • std.random: Major addition of engines and distributions.
  • std.format: Added raw ('r') format specifier for writef*.
  • std.path: Added rel2abs (Linux version only).
  • std.algorithm: new module
  • std.typecons: new module
  • std.functional: new module
  • std.numeric: new module
  • Added const/invariant structs, classes and interfaces.
  • Added const and invariant to IsExpressions.
  • Added typeof(return) type specifier.
  • Changed the way coverage analysis is done so it is independent of order dependencies among modules.
  • Revamped const/invariant.

Bugs Fixed

  • Bugzilla 70: valgrind: Conditional jump or move depends on uninitialised value(s) in elf_findstr
  • Bugzilla 71: valgrind: Invalid read of size 4 in elf_renumbersyms
  • Bugzilla 204: Error message on attempting to instantiate an abstract class needs to be improved
  • Bugzilla 1508: dmd/linux template symbol issues
  • Bugzilla 1651: .di file generated with -H switch does not translate function() arguments correctly
  • Bugzilla 1655: Internal error: ..\ztc\cgcod.c 1817
  • Bugzilla 1656: illegal declaration accepted
  • Bugzilla 1664: (1.23).stringof generates bad code
  • Bugzilla 1665: Internal error: ..\ztc\cod2.c 411
Version D 2.007 Oct 31, 2007

New/Changed Features

  • Functors now supported by std.traits.ReturnType().
  • Transitive const now leaves invariants intact in the tail.
  • Added overloadable unary * operation as opStar().
  • Full closure support added.
  • Data items in static data segment >= 16 bytes in size are now paragraph aligned.

Bugs Fixed

  • Variables of type void[0] can now be declared.
  • Static multidimensional arrays can now be initialized with other matching static multidimensional arrays.
  • Bugzilla 318: wait does not release thread resources on Linux
  • Bugzilla 322: Spawning threads which allocate and free memory leads to pause error on collect
  • Bugzilla 645: Race condition in std.thread.Thread.pauseAll
  • Bugzilla 689: Clean up the spec printfs!
  • Bugzilla 697: No const folding on asm db,dw, etc
  • Bugzilla 706: incorrect type deduction for array literals in functions
  • Bugzilla 708: inline assembler: "CVTPS2PI mm, xmm/m128" fails to compile
  • Bugzilla 709: inline assembler: "CVTPD2PI mm, xmm/m128" fails to compile
  • Bugzilla 718: Internal error: ../ztc/cgcod.c 562
  • Bugzilla 723: bad mixin of class definitions at function level: func.c:535: virtual void FuncDeclaration::semantic3(Scope*): Assertion `0' failed
  • Bugzilla 725: expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed.
  • Bugzilla 726: incorrect error line for "override" mixin
  • Bugzilla 729: scope(...) statement in SwitchBody causes compiler to segfault
  • Bugzilla 1258: Garbage collector loses memory upon array concatenation
  • Bugzilla 1480: std.stream throws the new override warning all over the place
  • Bugzilla 1483: Errors in threads not directed to stderr
  • Bugzilla 1557: std.zlib allocates void[]s instead of ubyte[]s, causing leaks.
  • Bugzilla 1580: concatenating invariant based strings should work
  • Bugzilla 1593: ICE compiler crash empty return statement in function
  • Bugzilla 1613: DMD hangs on syntax error
  • Bugzilla 1618: Typo in std\system.d
Version D 2.006 Oct 16, 2007

New/Changed Features

  • Transformed all of string, wstring, and dstring into invariant definitions. Tons of changes in function signatures and implementations rippled through the standard library. Initial experience with invariant strings seems to be highly encouraging.
  • Implemented Overload Sets for functions and templates.
  • Added the std.getopt module that makes standards-conforming command-line processing easy.
  • Added the parse and assumeUnique to the std.conv module.
  • Added the dirEntries function to the std.file module.
  • Added the basename and dirname functions (which alias the less gainful names getBaseName and getDirectoryName to the std.path module.)
  • Added optional terminator to readln; added the convenience functions fopen and popen; added functions lines and chunks; all to the std.stdio module.
  • Added the munch function to the std.string module.
  • Fixed isStaticArray; added BaseClassesTuple, TransitiveBaseTypeTuple, ImplicitConversionTargets, isIntegral, isFloatingPoint, isNumeric, isSomeString, isAssociativeArray, isDynamicArray, isArray; all to the std.traits module.
  • Added the std.variant module.
  • Incorporated many of the Tango GC structural differences (much more to go still).
  • Added the std.contracts module.
  • Breaking change: std.stdio.writef can now only accept a format as its first argument.

Bugs Fixed

  • Bugzilla 1478: Avoid libc network api threadsafety issues
  • Bugzilla 1491: Suppress SIGPIPE when sending to a dead socket
  • Bugzilla 1562: Deduction of template alias parameter fails
  • Bugzilla 1571: Const on function parameters not carried through to .di file
  • Bugzilla 1575: Cannot do assignment of tuples
  • Bugzilla 1579: write[ln] fails for obj.toString()
  • Bugzilla 1580: Concatenating invariant based strings should work
Version D 2.005 Oct 1, 2007

New/Changed Features

  • std.math.sin, cos, tan are now evaluated at compile time if the argument is a constant.
  • Added Cristian Vlasceanu's idea for C++ interface for 'plugins'
  • Overhaul phobos linux.mak and add documentation build logic
  • Massive additions to std.conv
  • Add writeln() and write() to std.stdio

Bugs Fixed

  • Fix std.boxer boxing of Object's (unit test failure)
  • Fix std.demangle to not show hidden parameters (this and delegate context pointers)
  • Bugzilla 217: typeof not working properly in internal/object.d
  • Bugzilla 218: Clean up old code for packed bit array support
  • Bugzilla 223: Error message for unset constants doesn't specify error location
  • Bugzilla 278: dmd.conf search path doesn't work
  • Bugzilla 479: can't compare arrayliteral statically with string
  • Bugzilla 549: A class derived from a deprecated class is not caught
  • Bugzilla 550: Shifting by more bits than size of quantity is allowed
  • Bugzilla 551: Modulo operator works with imaginary and complex operands
  • Bugzilla 556: is (Type Identifier : TypeSpecialization) doesn't work as it should
  • Bugzilla 668: Use of *.di files breaks the order of static module construction
  • Bugzilla 1125: Segfault using tuple in asm code, when size not specified
  • Bugzilla 1437: dmd crash: "Internal error: ..\ztc\cod4.c 357"
  • Bugzilla 1456: Cannot use a constant with alias template parameters
  • Bugzilla 1474: regression: const struct with an initializer not recognized as a valid alias template param
  • Bugzilla 1488: Bad code generation when using tuple from asm
  • Bugzilla 1510: ICE: Assertion failure: 'ad' on line 925 in file 'func.c'
  • Bugzilla 1523: struct literals not work with typedef
  • Bugzilla 1530: Aliasing problem in DMD front end code
  • Bugzilla 1531: cannot access typedef'd class field
  • Bugzilla 1537: Internal error: ..\ztc\cgcod.c 1521
Version D 2.004 Sep 5, 2007

New/Changed Features

  • Added command line switches -defaultlib and -debuglib
  • Bugzilla 1445: Add default library options to sc.ini / dmd.conf
  • Changed result type of IsExpression from int to bool.
  • Added isSame and compiles to __traits.
  • Added optional TemplateParameterList to IsExpression.
  • Added warning when override is omitted.
  • Added std.hiddenfunc.
  • Added trace_term() to object.d to fix Bugzilla 971: No profiling output is generated if the application terminates with exit
  • Multiple module static constructors/destructors allowed.
  • Added new syntax for string literals (delimited, heredoc, D tokens)
  • Added __EOF__ token

Bugs Fixed

  • Fixed D/56414
  • Bugzilla 961: std.windows.registry stack corruption
  • Bugzilla 1315: CTFE doesn't default initialise arrays of structs
  • Bugzilla 1342: struct const not accepted as initializer for another struct
  • Bugzilla 1363: Compile-time issue with structs in 'for'
  • Bugzilla 1375: CTFE fails for null arrays
  • Bugzilla 1378: A function call in an array literal causes compiler to crash
  • Bugzilla 1384: Compiler segfaults when using struct variable like a function with no opCall member.
  • Bugzilla 1388: multiple static constructors allowed in module
  • Bugzilla 1414: compiler crashes with CTFE and structs
  • Bugzilla 1421: Stack Overflow when using __traits(allMembers...)
  • Bugzilla 1423: Registry: corrupted value
  • Bugzilla 1436: std.date.getLocalTZA() returns wrong values when in DST under Windows
  • Bugzilla 1446: Missing comma in Final Const and Invariant page title
  • Bugzilla 1447: CTFE does not work for static member functions of a class
  • Bugzilla 1448: UTF-8 output to console is seriously broken
  • Bugzilla 1450: Registry: invalid UTF-8 sequence
  • Bugzilla 1460: Compiler crash on valid code
  • Bugzilla 1464: "static" foreach breaks CTFE
  • Bugzilla 1468: A bug about stack overflow.
Version D 2.003 Jul 21, 2007

New/Changed Features

  • Added 0x78 Codeview extension for type dchar.
  • Moved next member from Object.Error to Object.Exception
  • Added ForeachRangeStatement
    • .
  • Added extern (System)
  • Added std.traits
  • Bugzilla 345: updated std.uni.isUniAlpha to Unicode 5.0.0

Bugs Fixed

  • Bugzilla 46: Included man files should be updated
  • Bugzilla 268: Bug with SocketSet and classes
  • Bugzilla 406: std.loader is broken on linux
  • Bugzilla 561: Incorrect duplicate error message when trying to create instance of interface
  • Bugzilla 588: lazy argument and nested symbol support to std.demangle
  • Bugzilla 668: Use of *.di files breaks the order of static module construction
  • Bugzilla 1110: std.format.doFormat + struct without toString() == crash
  • Bugzilla 1300: Issues with struct in compile-time function
  • Bugzilla 1306: extern (Windows) should work like extern (C) for variables
  • Bugzilla 1318: scope + ref/out parameters are allowed, contrary to spec
  • Bugzilla 1320: Attributes spec uses 1.0 const semantics in 2.0 section
  • Bugzilla 1331: header file genaration generates a ":" instead of ";" at pragma
  • Bugzilla 1332: Internal error: ../ztc/cod4.c 357
  • Bugzilla 1333: -inline ICE: passing an array element to an inner class's constructor in a nested function, all in a class or struct
  • Bugzilla 1336: Internal error when trying to construct a class declared within a unittest from a templated class.
Version D 2.002 Jul 1, 2007

New/Changed Features

  • Renamed linux library from libphobos.a to libphobos2.a

Bugs Fixed

  • Bugzilla 540: Nested template member function error - "function expected before ()"
  • Bugzilla 559: Final has no effect on methods
  • Bugzilla 627: Concatenation of strings to string arrays with ~ corrupts data
  • Bugzilla 629: Misleading error message "Can only append to dynamic arrays"
  • Bugzilla 639: Escaped tuple parameter ICEs dmd
  • Bugzilla 641: Complex string operations in template argument ICEs dmd
  • Bugzilla 657: version(): ignored
  • Bugzilla 689: Clean up the spec printfs!
  • Bugzilla 1103: metastrings.ToString fails for long > 0xFFFF_FFFF
  • Bugzilla 1107: CodeView: wrong CV type for bool
  • Bugzilla 1118: weird switch statement behaviour
  • Bugzilla 1186: Bind needs a small fix
  • Bugzilla 1199: Strange error messages when indexing empty arrays or strings at compile time
  • Bugzilla 1200: DMD crash: some statements containing only a ConditionalStatement with a false condition
  • Bugzilla 1203: Cannot create Anonclass in loop
  • Bugzilla 1204: segfault using struct in CTFE
  • Bugzilla 1206: Compiler hangs on this() after method in class that forward references struct
  • Bugzilla 1207: Documentation on destructors is confusing
  • Bugzilla 1211: mixin("__LINE__") gives incorrect value
  • Bugzilla 1212: dmd generates bad line info
  • Bugzilla 1216: Concatenation gives 'non-constant expression' outside CTFE
  • Bugzilla 1217: Dollar ($) seen as non-constant expression in non-char[] array
  • Bugzilla 1219: long.max.stringof gets corrupted
  • Bugzilla 1224: Compilation does not stop on asserts during CTFE
  • Bugzilla 1228: Class invariants should not be called before the object is fully constructed
  • Bugzilla 1233: std.string.ifind(char[] s, char[] sub) fails on certain non ascii strings
  • Bugzilla 1234: Occurrence is misspelled almost everywhere
  • Bugzilla 1235: std.string.tolower() fails on certain utf8 characters
  • Bugzilla 1236: Grammar for Floating Literals is incomplete
  • Bugzilla 1239: ICE when empty tuple is passed to variadic template function
  • Bugzilla 1242: DMD AV
  • Bugzilla 1244: Type of array length is unspecified
  • Bugzilla 1247: No time zone info for India
  • Bugzilla 1285: Exception typedefs not distinguished by catch
  • Bugzilla 1287: Iterating over an array of tuples causes "glue.c:710: virtual unsigned int Type::totym(): Assertion `0' failed."
  • Bugzilla 1290: Two ICEs, both involving real, imaginary, ? : and +=.
  • Bugzilla 1291: .stringof for a class type returned from a template doesn't work
  • Bugzilla 1292: Template argument deduction doesn't work
  • Bugzilla 1294: referencing fields in static arrays of structs passed as arguments generates invalid code
  • Bugzilla 1295: Some minor errors in the lexer grammar
Version D 2.001 Jun 27, 2007

New/Changed Features

  • Added D_Version2 predefined identifier to indicate this is a D version 2.0 compiler
  • Added __VENDOR__ and __VERSION__.
  • Now an error to use both const and invariant as storage classes for the same declaration
  • The .init property for a variable is now based on its type, not its initializer.

Bugs Fixed

  • std.compiler now is automatically updated.
  • Fixed problem catting mutable to invariant arrays.
  • Fixed CFTE bug with e++ and e--.
  • Bugzilla 1254: Using a parameter initialized to void in a compile-time evaluated function doesn't work
  • Bugzilla 1256: "with" statement with symbol
  • Bugzilla 1259: Inline build triggers an illegal error msg "Error: S() is not an lvalue"
  • Bugzilla 1260: Another tuple bug
  • Bugzilla 1261: Regression from overzealous error message
  • Bugzilla 1262: Local variable of struct type initialized by literal resets when compared to .init
  • Bugzilla 1263: Template function overload fails when overloading on both template and non-template class
  • Bugzilla 1268: Struct literals try to initialize static arrays of non-static structs incorrectly
  • Bugzilla 1269: Compiler crash on assigning to an element of a void-initialized array in CTFE
  • Bugzilla 1270: -inline produces an ICE
  • Bugzilla 1272: problems with the new 1.0 section
  • Bugzilla 1274: 2.0 beta link points to dmd.zip which is the 1.x chain
  • Bugzilla 1275: ambiguity with 'in' meaning
  • Bugzilla 1276: static assert message displayed with escaped characters
  • Bugzilla 1277: "in final const scope" not considered redundant storage classes
  • Bugzilla 1279: const/invariant functions don't accept const/invariant return types
  • Bugzilla 1280: std.socket.Socket.send (void[],SocketFlags) should take a const(void)[] instead
  • Bugzilla 1283: writefln: formatter applies to following variable
  • Bugzilla 1286: crash on invariant struct member function referencing globals
Version D 2.000 Jun 17, 2007

New/Changed Features

  • Added aliases string, wstring, and dstring for strings.
  • Added .idup property for arrays to create invariant copies.
  • Added const, invariant, and final.
  • in parameter storage class now means final scope const.
  • foreach value variables now default to final if not declared as inout.
  • class and struct invariant declarations now must have a ().

Bugs Fixed

  • Added missing \n to exception message going to stderr.
  • Fixed default struct initialization for CTFE.
  • Bugzilla 1226: ICE on a struct literal
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


D 2.0 FAQ - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

D 2.0 FAQ

The same questions keep cropping up, so the obvious thing to do is prepare a FAQ.

D 1.0 FAQ

C++ FAQ

D 2.0 FAQ

  • What's the difference between D 2.0 and D 1.0?
  • Where is my simple language?
  • What other cool features are in the plans for D 2.0?
  • I suggested a great feature. Why was the suggestion ignored?
  • Why const and immutable?
  • Why the names const and immutable?
  • How exactly is immutable related to multicores?
  • Ok, I'm fine with immutable for safe data sharing among threads. But why do we need the uninformative const?
  • Why are immutable strings favored in D 2.0?
  • I want to contribute to D 2.0. How can I effect that?
  • Why doesn't the case range statement use the case X..Y: syntax?
  • What guarantees is shared supposed to provide?
  • What does shared have to do with synchronization?
  • What does shared have to do with memory barriers?
  • What are the semantics of casting FROM unshared TO shared?
  • What are the semantics of casting FROM shared TO unshared?
  • Why does a large static array bloat my executable file size?

General D FAQ

  • The D wiki FAQ page with many more questions answered
  • What does D have that C++ doesn't?
  • Why the name D?
  • Could you change the name? D is kind of hard to search for on search engines.
  • Where can I get a D compiler?
  • Is there linux port of D?
  • Is there a GNU version of D?
  • How do I write my own D compiler for CPU X?
  • Where can I get a GUI library for D?
  • Where can I get an IDE for D?
  • Why is [expletive deleted] printf left in?
  • Is D open source?
  • Why does the standard library use the boost license? Why not public domain?
  • Why no fall through on switch statements?
  • Why should I use D instead of Java?
  • Doesn't C++ support strings, etc. with STL?
  • Can't garbage collection be done in C++ with an add-on library?
  • Can't unit testing be done in C++ with an add-on library?
  • Why have an asm statement in a portable language?
  • What is the point of 80 bit reals?
  • How do I do anonymous struct/unions in D?
  • How do I get printf() to work with strings?
  • Why are floating point values default initialized to NaN rather than 0?
  • Why is overloading of the assignment operator not supported?
  • The ‘~’ is not on my keyboard?
  • Can I link in C object files created with another compiler?
  • Why not support regular expression literals with the /foo/g syntax?
  • Why is the D front end written in C++ rather than D?
  • Why aren't all Digital Mars programs translated to D?
  • When should I use a foreach loop rather than a for?
  • Why doesn't D have an interface to C++ as well as C?
  • Why doesn't D use reference counting for garbage collection?
  • Isn't garbage collection slow and non-deterministic?
  • Can't a sufficiently smart compiler figure out that a function is pure automatically?
  • Why allow cast(float) if it isn't supposed to work?
  • Why can't nested functions be forward referenced?

Why doesn't the case range statement use the case X..Y: syntax?

See the case range statement.

The usages of .. would then be:

  1. case X..Y:
  2. foreach(e; X..Y)
  3. array[X..Y]
Case (1) has a VERY DIFFERENT meaning from (2) and (3). (1) is inclusive of Y, and (2) and (3) are exclusive of Y. Having a very different meaning means it should have a distinctly different syntax.

What guarantees is shared supposed to provide?

Shared means that multiple threads can access the data. The guarantee is that if it is not shared, and not immutable, that only the current thread can see it.

What does shared have to do with synchronization?

Only shared data can be synchronized. It makes no sense to synchronize thread local data.

What does shared have to do with memory barriers?

Reading/writing shared data emits memory barriers to ensure sequential consistency (not implemented).

What are the semantics of casting FROM unshared TO shared?

Make sure there are no other unshared references to that same data.

What are the semantics of casting FROM shared TO unshared?

Make sure there are no other shared references to that same data.

Why does a large static array bloat my executable file size?

Given the declaration:

char[1024 * 1024] arr;

the executable size increases by a megabyte in size. In C, this would not as arr would be stored in the BSS segment. In D, arr is not stored in the BSS segment because:

  • The char type is initialized to 0xFF, not 0. Non-zero data cannot be placed in BSS.
  • Statically allocated data is placed in thread local storage. The BSS segment is not thread local, and there is no thread local equivalent of BSS.

The following will be placed in BSS:

__gshared byte[1024 * 1024] arr;

as bytes are 0 initialized and __gshared puts it in the global data.

There are similiar issues for float, double, and real static arrays. They are initialized to NaN (Not A Number) values, not 0.

The easiest way to deal with this issue is to allocate the array dynamically at run time rather than statically allocate it.

Why the name D?

The original name was the Mars Programming Language. But my friends kept calling it D, and I found myself starting to call it D. The idea of D being a successor to C goes back at least as far as 1988, as in this thread.

Could you change the name? D is kind of hard to search for on search engines.

No. We understand it can be frustrating but it's far too late for a name change at this point. We recommend using "dlang", "d programming", "d language", or "d programming language" in your search terms. Doing so should yield substantially better search results.

Most publically available D code has "// Written in the D programming language" as its first comment.

Is there a linux port of D?

Yes, the D compiler includes a linux version.

Is there a GNU version of D?

Yes, gdc - the D frontend with GCC.

How do I write my own D compiler for CPU X?

Burton Radons has written a back end. You can use as a guide.

Where can I get a GUI library for D?

Since D can call C functions, any GUI library with a C interface is accessible from D. Various D GUI libraries and ports can be found at the D wiki.

Where can I get an IDE for D?

A list of IDEs and editors that support D can be found on the D wiki.

Why is printf in D?

printf is not part of D, it is part of C's standard runtime library which is accessible from D. D's standard runtime library has std.stdio.writefln, which is as powerful as printf but is much easier to use.

Is D open source?

The front end for the dmd D compiler is open source. The back end for dmd is licensed from Symantec, and is not compatible with open-source licenses such as the GPL. Nonetheless, the complete source comes with the compiler, and all development takes place publically on github. Compilers using the DMD front end and the GCC and LLVM open source backends are also available. The runtime library is completely open source using the Boost License 1.0. The gdc and ldc D compilers are completely open sourced.

Why does the standard library use the boost license? Why not public domain?

Although most jurisdictions use the concept of Public Domain, some (eg, Japan) do not. The Boost License avoids this problem. It was chosen because, unlike almost all other open source licenses, it does not demand that the license text be included on distributions in binary form.

Why no fall through on switch statements?

Many people have asked for a requirement that there be a break between cases in a switch statement, that C's behavior of silently falling through is the cause of many bugs.

In D2, implicit fall through is disallowed. You have to add a goto case; statement to explicitly state the intention of falling through.

There was further request that the break statement be made implicit. The reason D doesn't change this is for the same reason that integral promotion rules and operator precedence rules were kept the same - to make code that looks the same as in C operate the same. If it had subtly different semantics, it will cause frustratingly subtle bugs.

Why should I use D instead of Java?

D is distinct from Java in purpose, philosophy and reality. See this comparison.

Java is designed to be write once, run everywhere. D is designed for writing efficient native system apps. Although D and Java share the notion that garbage collection is good and multiple inheritance is bad, their different design goals mean the languages have very different feels.

Doesn't C++ support strings, etc. with STL?

In the C++ standard library are mechanisms for doing strings, dynamic arrays, associative arrays, and bounds-checked arrays.

Sure, all this stuff can be done with libraries, following certain coding disciplines, etc. But object oriented programming can also be done in C (it's been done). Isn't it incongruous that something like strings, supported by the simplest BASIC interpreter, requires a very large and complicated infrastructure to support? Just the implementation of a string type in STL is over two thousand lines of code, using every advanced feature of templates. How much confidence can you have that this is all working correctly, how do you fix it if it is not, what do you do with the notoriously inscrutable error messages when there's an error using it, how can you be sure you are using it correctly (so there are no memory leaks, etc.)?

D's implementation of strings is simple and straightforward. There's little doubt about how to use it, no worries about memory leaks, error messages are to the point, and it isn't hard to see if it is working as expected or not.

Can't garbage collection be done in C++ with an add-on library?

Yes, I use one myself. It isn't part of the language, though, and requires some subverting of the language to make it work. Using gc with C++ isn't for the standard or casual C++ programmer. Building it into the language, like in D, makes it practical for everyday programming chores.

GC isn't that hard to implement, either, unless you're building one of the more advanced ones. But a more advanced one is like building a better optimizer - the language still works 100% correctly even with a simple, basic one. The programming community is better served by multiple implementations competing on quality of code generated rather than by which corners of the spec are implemented at all.

Can't unit testing be done in C++ with an add-on library?

Sure. Try one out and then compare it with how D does it. It'll be quickly obvious what an improvement building it into the language is.

Why have an asm statement in a portable language?

An asm statement allows assembly code to be inserted directly into a D function. Assembler code will obviously be inherently non-portable. D is intended, however, to be a useful language for developing systems apps. Systems apps almost invariably wind up with system dependent code in them anyway, inline asm isn't much different. Inline asm will be useful for things like accessing special CPU instructions, accessing flag bits, special computational situations, and super optimizing a piece of code.

Before the C compiler had an inline assembler, I used external assemblers. There was constant grief because many, many different versions of the assembler were out there, the vendors kept changing the syntax of the assemblers, there were many different bugs in different versions, and even the command line syntax kept changing. What it all meant was that users could not reliably rebuild any code that needed assembler. An inline assembler provided reliability and consistency.

What is the point of 80 bit reals?

More precision enables more accurate floating point computations to be done, especially when adding together large numbers of small real numbers. Prof. Kahan, who designed the Intel floating point unit, has an eloquent paper on the subject.

How do I do anonymous struct/unions in D?

import std.stdio;

struct Foo
{
    union { int a; int b; }
    struct { int c; int d; }
}

void main()
{
    writefln(
      "Foo.sizeof = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d",
      Foo.sizeof,
      Foo.a.offsetof,
      Foo.b.offsetof,
      Foo.c.offsetof,
      Foo.d.offsetof);
}

How do I get printf() to work with strings?

In C, the normal way to printf a string is to use the %s format:
char s[8];
strcpy(s, "foo");
printf("string = '%s'\n", s);
Attempting this in D, as in:
char[] s;
s = "foo";
printf("string = '%s'\n", s);
usually results in garbage being printed, or an access violation. The cause is that in C, strings are terminated by a 0 character. The %s format prints until a 0 is encountered. In D, strings are not 0 terminated, the size is determined by a separate length value. So, strings are printf'd using the %.*s format:
char[] s;
s = "foo";
printf("string = '%.*s'\n", s);

which will behave as expected. Remember, though, that printf's %.*s will print until the length is reached or a 0 is encountered, so D strings with embedded 0's will only print up to the first 0.

Of course, the easier solution is just use std.stdio.writefln which works correctly with D strings.

Why are floating point values default initialized to NaN rather than 0?

A floating point value, if no explicit initializer is given, is initialized to NaN (Not A Number):
double d;	// d is set to double.nan
NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.

If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.

The default initializer value is not meant to be a useful value, it is meant to expose bugs. Nan fills that role well.

But surely the compiler can detect and issue an error message for variables used that are not initialized? Most of the time, it can, but not always, and what it can do is dependent on the sophistication of the compiler's internal data flow analysis. Hence, relying on such is unportable and unreliable.

Because of the way CPUs are designed, there is no NaN value for integers, so D uses 0 instead. It doesn't have the advantages of error detection that NaN has, but at least errors resulting from unintended default initializations will be consistent and therefore more debuggable.

Why is overloading of the assignment operator not supported?

Overloading of the assignment operator for structs is supported in D 2.0.

The ‘~’ is not on my keyboard?

On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 keys in sequence on the numeric pad. That will generate a ‘~’ character.

Can I link in C object files created with another compiler?

DMD produces OMF (Microsoft Object Module Format) object files while other compilers such as VC++ produce COFF object files. DMD's output is designed to work with DMC, the Digital Mars C compiler, which also produces object files in OMF format.

The OMF format that DMD uses is a Microsoft defined format based on an earlier Intel designed one. Microsoft at one point decided to abandon it in favor of a Microsoft defined variant on COFF.

Using the same object format doesn't mean that any C library in that format will successfully link and run. There is a lot more compatibility required - such as calling conventions, name mangling, compiler helper functions, and hidden assumptions about the way things work. If DMD produced Microsoft COFF output files, there is still little chance that they would work successfully with object files designed and tested for use with VC. There were a lot of problems with this back when Microsoft's compilers did generate OMF.

Having a different object file format makes it helpful in identifying library files that were not tested to work with DMD. If they are not, weird problems would result even if they successfully managed to link them together. It really takes an expert to get a binary built with a compiler from one vendor to work with the output of another vendor's compiler.

That said, the linux version of DMD produces object files in the ELF format which is standard on linux, and it is specifically designed to work with the standard linux C compiler, gcc.

There is one case where using existing C libraries does work - when those libraries come in the form of a DLL conforming to the usual C ABI interface. The linkable part of this is called an "import library", and Microsoft COFF format import libraries can be successfully converted to DMD OMF using the coff2omf tool.

Why not support regular expression literals with the /foo/g syntax?

There are two reasons:

  1. The /foo/g syntax would make it impossible to separate the lexer from the parser, as / is the divide token.
  2. There are already 3 string types; adding the regex literals would add 3 more. This would proliferate through much of the compiler, debugger info, and library, and is not worth it.

Why is the D front end written in C++ rather than D?

The front end is in C++ in order to interface to the existing gcc and dmd back ends. It's also meant to be easily interfaced to other existing back ends, which are likely written in C++. The D implementation of DMDScript, which performs better than the C++ version, shows that there is no problem writing a professional quality compiler in 100% D.

Why aren't all Digital Mars programs translated to D?

There is little benefit to translating a complex, debugged, working application from one language to another. But new Digital Mars apps are implemented in D.

When should I use a foreach loop rather than a for?

Is it just performance or readability?

By using foreach, you are letting the compiler decide on the optimization rather than worrying about it yourself. For example - are pointers or indices better? Should I cache the termination condition or not? Should I rotate the loop or not? The answers to these questions are not easy, and can vary from machine to machine. Like register assignment, let the compiler do the optimization.

for (int i = 0; i < foo.length; i++)
or:
for (int i = 0; i < foo.length; ++i)
or:
for (T* p = &foo[0]; p < &foo[length]; p++)
or:
T* pend = &foo[length];
for (T* p = &foo[0]; p < pend; ++p)
or:
T* pend = &foo[length];
T* p = &foo[0];
if (p < pend)
{
    do
    {
    ...
    } while (++p < pend);
}
and, of course, should I use size_t or int?
for (size_t i = 0; i < foo.length; i++)
Let the compiler pick!
foreach (v; foo)
    ...

Note that we don't even need to know what the type T needs to be, thus avoiding bugs when T changes. I don't even have to know if foo is an array, or an associative array, or a struct, or a collection class. This will also avoid the common fencepost bug:

for (int i = 0; i <= foo.length; i++)

And it also avoids the need to manually create a temporary if foo is a function call.

The only reason to use a for loop is if your loop does not fit in the conventional form, like if you want to change the termination condition on the fly.

Why doesn't D have an interface to C++ as well as C?

D 2.0 does have a limited interface to C++ code.

Here are some reasons why it isn't a full interface:

Attempting to have D interface with C++ is nearly as complicated as writing a C++ compiler, which would destroy the goal of having D be a reasonably easy language to implement. For people with an existing C++ code base that they must work with, they are stuck with C++ (they can't move it to any other language, either).

There are many issues that would have to be resolved in order for D code to call some arbitrary C++ code that is presumed to be unmodifiable. This list certainly isn't complete, it's just to show the scope of the difficulties involved.

  1. D source code is unicode, C++'s is ASCII with code pages. Or not. It's unspecified. This impacts the contents of string literals.
  2. std::string cannot deal with multibyte UTF.
  3. C++ has a tag name space. D does not. Some sort of renaming would have to happen.
  4. C++ code often relies on compiler specific extensions.
  5. C++ has namespaces. D has modules. There is no obvious mapping between the two.
  6. C++ views source code as one gigantic file (after preprocessing). D sees source code as a hierarchy of modules and packages.
  7. Enum name scoping rules behave differently.
  8. C++ code, despite decades of attempts to replace macro features with inbuilt ones, relies more heavily than ever on layer after layer of arbitrary macros. D does not always have an analog for token pasting and stringizing.
  9. Macro names have global scope across #include files, but are local to the gigantic source files.
  10. C++ has arbitrary multiple inheritance and virtual base classes. D does not.
  11. C++ does not distinguish between in, out and ref (i.e. inout) parameters.
  12. The C++ name mangling varies from compiler to compiler.
  13. C++ throws exceptions of arbitrary type, not just descendants of Object.
  14. C++ overloads based on const and volatile. D overloads based on const and immutable.
  15. C++ overloads operators in significantly different ways - for example, operator[]() overloading for lvalue and rvalue is based on const overloading and a proxy class.
  16. C++ overloads operators like < completely independently of >.
  17. C++ does not distinguish between a class and a struct object.
  18. The vtbl[] location and layout is different between C++ and D.
  19. The way RTTI is done is completely different. C++ has no classinfo.
  20. D does not have two phase lookup, nor does it have Koenig (ADL) lookup.
  21. C++ relates classes with the 'friend' system, D uses packages and modules.
  22. C++ class design tends to revolve around explicit memory allocation issues, D's do not.
  23. D's template system is very different.
  24. C++ has 'exception specifications'.
  25. C++ has global operator overloading.
  26. C++ name mangling depends on const and volatile being type modifiers. D name mangling depends on const and immutable being type modifiers. D's const is also transitive, unlike C++. One cannot have a const pointer to mutable in D.

The bottom line is the language features affect the design of the code. C++ designs just don't fit with D. Even if you could find a way to automatically adapt between the two, the result will be about as enticing as the left side of a honda welded to the right side of a camaro.

Why doesn't D use reference counting for garbage collection?

Reference counting has its advantages, but some severe disadvantages:

  • Cyclical data structures won't get freed.
  • Every pointer copy requires an increment and a corresponding decrement - including when simply passing a reference to a function.
  • In a multithreaded app, the incs and decs must be synchronized.
  • Exception handlers (finally blocks) must be inserted to handle all the decs so there are no leaks. Contrary to assertions otherwise, there is no such thing as "zero overhead exceptions."
  • In order to support slicing and interior pointers, as well as supporting reference counting on arbitrary allocations of non-object data, a separate "wrapper" object must be allocated for each allocation to be ref counted. This essentially doubles the number of allocations needed.
  • The wrapper object will mean that all pointers will need to be double-dereferenced to access the data.
  • Fixing the compiler to hide all this stuff from the programmer will make it difficult to interface cleanly with C.
  • Ref counting can fragment the heap thereby consuming more memory just like the gc can, though the gc typically will consume more memory overall.
  • Ref counting does not eliminate latency problems, it just reduces them.

The proposed C++ shared_ptr<>, which implements ref counting, suffers from all these faults. I haven't seen a heads up benchmark of shared_ptr<> vs mark/sweep, but I wouldn't be surprised if shared_ptr<> turned out to be a significant loser in terms of both performance and memory consumption.

That said, D may in the future optionally support some form of ref counting, as rc is better for managing scarce resources like file handles. Furthermore, if ref counting is a must, Phobos has the std.typecons.RefCounted type which implements it as a library, similar to C++'s shared_ptr<>.

Isn't garbage collection slow and non-deterministic?

Yes, but all dynamic memory management is slow and non-deterministic, including malloc/free. If you talk to the people who actually do real time software, they don't use malloc/free precisely because they are not deterministic. They preallocate all data. However, the use of GC instead of malloc enables advanced language constructs (especially, more powerful array syntax), which greatly reduce the number of memory allocations which need to be made. This can mean that GC is actually faster than explict management.

Can't a sufficiently smart compiler figure out that a function is pure automatically?

The compiler infers purity (and safety, and nothrow) for delegate and function literals. It doesn't do this for normal functions for several reasons:

  1. most functions call other functions, which call other functions, until one of them calls a library routine whose source is not available to the compiler. So it will have to assume it is not pure. With a pure function attribute, external library functions that are pure can be marked as pure, and then the analysis can work for enough cases to be useful.
  2. Since virtual functions (and by extension delegates and function pointers) can be extended by the user at times the compiler won't see it, they have to be assumed to be impure.
  3. If the programmer intends for a particular function to be pure and the compiler detects it is not, this may go unnoticed by the programmer. Even worse, if the programmer does notice it, it may be arbitrarily difficult to determine why the compiler thinks it is impure - is it a programming mistake or a compiler bug?

Why allow cast(float) if it isn't supposed to work?

The floating point rules are such that transforming cast(real)cast(float) to cast(real) is a valid transformation. This is because the floating point rules are written with the following principle in mind:

An algorithm is invalid if it breaks if the floating point precision is increased. Floating point precision is always a minimum, not a maximum.

Programs that legitimately depended on maximum precision are:

  1. compiler/library validation test suites
  2. ones trying to programmatically test the precision

(1) is not of value to user programming, and there are alternate ways to test the precision.

(2) D has .properties that take care of that.

Programs that rely on a maximum accuracy need to be rethought and reengineered.

Why can't nested functions be forward referenced?

Declarations within a function are different from declarations at module scope. Within a function, initializers for variable declarations are guaranteed to run in sequential order. Allowing arbitrary forward references to nested functions would break this, because nested functions can reference any variables declared above them.

    int first() {  return second();    }
    int x = first();   // x depends on y, which hasn't been declared yet.
    int y = x + 1;
    int second() {  return y;    }

But, forward references of nested functions are sometimes required (eg, for mutually recursive nested functions). The most general solution is to declare a local, nested struct. Any member functions (and variables!) of that struct have non-sequential semantics, so they can forward reference each other.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


const(FAQ) - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

const(FAQ)

D's const/immutable system is unique, and so there are a lot of questions about it.

  • Why does D have const?
  • What principles drove the D const design?
  • What is transitive const?
  • What is head const?
  • What is tail const?
  • What is logical const?
  • Why not use readonly to mean read only view?
  • Why did Java reject const?
  • How does const differ in C++?
  • Why are strings immutable?
  • Why aren't function parameters const by default?
  • Are static class members covered by transitive const?
  • What is immutable good for?

Why does D have const?

People often express frustration with const and immutable in D 2.0 and wonder if it is worth it.

  1. It makes function interfaces more self-documenting. Without transitive const, for all pointer/reference parameters one must rely on the documentation (which is always missing, out of date, or wrong). Note that without transitivity, C++ const is nearly useless for such self-documentation, which is why C++ programmers tend to rely on convention instead.
  2. It makes for interfaces that can be relied upon, which becomes increasingly important the more people that are involved with the code. In other words, it scales very well. People who are involved with projects with large teams of programmers say that lack of const makes their lives difficult because they cannot rely on the compiler to enforce convention. The larger the team, the worse it gets. Managing APIs is critical to a large project - it's why BASIC doesn't scale (for an extreme example).
  3. Const transitivity makes for some interesting optimization opportunities. The value of this has not been explored or exploited.
  4. Here's the biggie. Points 1..3 are insignificant in comparison. The future of programming will be multicore, multithreaded. Languages that make it easy to program them will supplant languages that don't. Transitive const is key to bringing D into this paradigm. The surge in use of Haskell and Erlang is evidence of this coming trend (the killer feature of those languages is they make it easy to do multiprogramming). C++ cannot be retrofitted to supporting multiprogramming in a manner that makes it accessible. D isn't there yet, but it will be, and transitive const will be absolutely fundamental to making it work.

Of course, for writing single-threaded one man programs of fairly modest size, const is not particularly useful. And in D const can be effectively ignored by just not using it, or by using D 1.0. The only place const is imposed is with the immutable string type.

What principles drove the D const design?

  1. It will be mathematically sound. That means there are no legal escapes from it.
  2. Any type can be wrapped in a struct and the resulting struct can still exhibit the same const behavior - in other words, no magic behavior for certain types.
  3. Const behavior will be transitive.
  4. Const behavior for type T will be equivalent for all types T.

What is transitive const?

Transitive const means that once const is applied to a type, it applies recursively to every sub-component of that type. Hence:

const(int*)** p;
p += 1;   // ok, p is mutable
*p += 1;  // ok, *p is mutable
**p += 1; // error, **p is const
***p += 1; // error, ***p is const

With transitivity, there is no way to have a const pointer to mutable int.

C++ const is not transitive.

What is head const?

Head const is where the const applies only to the component of the type adjacent to the const. For example:

headconst(int**) p;

would be read as p being a: const pointer to mutable pointer to mutable int. D does not have head const (the headconst is there just for illustrative purposes), but C++ const is a head const system.

What is tail const?

Tail const is the complement of head const - everything reachable from the const type is also const except for the top level. For example:

tailconst(int**) p;

would be read as p being a: mutable pointer to const pointer to const int. Head const combined with tail const yields transitive const. D doesn't have tailconst (the keyword is there just for illustrative purposes) as a distinct type constructor.

What is logical const?

Logical const refers to data that appears to be constant to an observer, but is not actually const. An example would be an object that does lazy evaluation:

struct Foo {
    mutable int len;
    mutable bool len_done;
    const char* str;
    int length()
    {   if (!len_done)
        {   len = strlen(str);
        len_done = true;
        }
    return len;
    }
    this(char* str) { this.str = str; }
}
const Foo f = Foo("hello");
bar(f.length);

The example evaluates f.len only if it is needed. Foo is logically const, because to the observer of the object its return values never change after construction. The mutable qualifier says that even if an instance of Foo is const, those fields can still change. While C++ supports the notion of logical const, D does not, and D does not have a mutable qualifier.

The problem with logical const is that const is no longer transitive. Not being transitive means there is the potential for threading race conditions, and there is no way to determine if an opaque const type has mutable members or not.

Reference: mutable: bitwise vs. logical const

Why not use readonly to mean read only view?

Readonly has a well established meaning in software to mean ROM, or Read Only Memory that can never be changed. For computers with hardware protection for memory pages, readonly also means that the memory contents cannot be altered. Using readonly in D to mean a read only view of memory that could be altered by another alias or thread runs counter to this.

Why did Java reject const?

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

How does const differ in C++?

C++ has a const system that is closer to D's than any other language, but it still has huge differences:

  1. const is not transitive
  2. no immutables
  3. const objects can have mutable members
  4. const can be legally cast away and the data modified
  5. const T and T are not always distinct types

Why are strings immutable?

Immutable Strings

Why aren't function parameters const by default?

Since most (nearly all?) function parameters will not be modified, it would seem to make sense to make them all const by default, and one would have to specifically mark as mutable those that would be changed. The problems with this are:

  1. It would be a huge break from past D practice, and practice in C, C++, Java, C#, etc.
  2. It would require a new keyword, say mutable.
  3. And worst, it would make declarations inconsistent:
    void foo(int* p) {
   int* q;
   ...
}
    p points to const, and q points to mutable. This kind of inconsistency leads to all sorts of mistakes. It also makes it very hard to write generic code that deals with types.

Using in can mitigate the ugliness of having to annotate with const:

void str_replace(in char[] haystack, in char[] needle);

Are static class members covered by transitive const?

A static class member is part of the global state of a program, not part of the state of an object. Thus, a class having a mutable static member does not violate the transitive constness of an object of that class.

What is immutable good for?

Immutable data, once initialized, is never changed. This has many uses:

  • Access to immutable data need not be synchronized when multiple threads read it.
  • Data races, tearing, sequential consistency, and cache consistency are all non-issues when working with immutable data.
  • Pure functions can only accept immutable parameters.
  • When doing a deep copy of a data structure, the immutable portions need not be copied.
  • Invariance allows a large chunk of data to be treated as a value type even if it is passed around by reference (strings are the most common case of this).
  • Immutable type provides more self-documenting information to the programmer.
  • Immutable data can be placed in hardware protected read-only memory, or even in ROMs.
  • If immutable data does change, it is a sure sign of a memory corruption bug, and it is possible to automatically check for such data integrity.
  • Immutable types provide for many program optimization opportunities.

const acts as a bridge between the mutable and immutable worlds, so a single function can be used to accept both types of arguments.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Rationale - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Rationale

Questions about the reasons for various design decisions for D often come up. This addresses many of them.

Operator Overloading

Why not name them operator+(), operator*(), etc.?

This is the way C++ does it, and it is appealing to be able to refer to overloading ‘+’ with ‘operator+’. The trouble is things don't quite fit. For example, there are the comparison operators <, <=, >, and >=. In C++, all four must be overloaded to get complete coverage. In D, only a cmp() function must be defined, and the comparison operations are derived from that by semantic analysis.

Overloading operator/() also provides no symmetric way, as a member function, to overload the reverse operation. For example,

class A
{
    int operator/(int i);		// overloads (a/i)
    static operator/(int i, A a)	// overloads (i/a)
}

The second overload does the reverse overload, but it cannot be virtual, and so has a confusing asymmetry with the first overload.

Why not allow globally defined operator overload functions?

  1. Operator overloading can only be done with an argument as an object, so they logically belong as member functions of that object. That does leave the case of what to do when the operands are objects of different types:
    class A { }
class B { }
int opAdd(class A, class B);
    Should opAdd() be in class A or B? The obvious stylistic solution would be to put it in the class of the first operand,
    class A
{
    int opAdd(class B) { }
}
  2. Operator overloads usually need access to private members of a class, and making them global breaks the object oriented encapsulation of a class.
  3. (2) can be addressed by operator overloads automatically gaining "friend" access, but such unusual behavior is at odds with D being simple.

Why not allow user definable operators?

These can be very useful for attaching new infix operations to various unicode symbols. The trouble is that in D, the tokens are supposed to be completely independent of the semantic analysis. User definable operators would break that.

Why not allow user definable operator precedence?

The trouble is this affects the syntax analysis, and the syntax analysis is supposed to be completely independent of the semantic analysis in D.

Why not use operator names like __add__ and __div__ instead of opAdd, opDiv, etc.?

__ keywords should indicate a proprietary language extension, not a basic part of the language.

Why not have binary operator overloads be static members, so both arguments are specified, and there no longer is any issue with the reverse operations?

This means that the operator overload cannot be virtual, and so likely would be implemented as a shell around another virtual function to do the real work. This will wind up looking like an ugly hack. Secondly, the opCmp() function is already an operator overload in Object, it needs to be virtual for several reasons, and making it asymmetric with the way other operator overloads are done is unnecessary confusion.

Properties

Why does D have properties like T.infinity in the core language to give the infinity of a floating point type, rather than doing it in a library like C++: std::numeric_limits::infinity ?

Let's rephrase that as “if there's a way to express it in the existing language, why build it in to the core language?” In regards to T.infinity:
  1. Building it in to the core language means the core language knows what a floating point infinity is. Being layered in templates, typedefs, casts, const bit patterns, etc., it doesn't know what it is, and is unlikely to give sensible error messages if misused.
  2. A side effect of (1) is it is unlikely to be able to use it effectively in constant folding and other optimizations.
  3. Instantiating templates, loading #include files, etc., all costs compile time and memory.
  4. The worst, though, is the lengths gone to just to get at infinity, implying “the language and compiler don't know anything about IEEE 754 floating point - so it cannot be relied on.” And in fact many otherwise excellent C++ compilers do not handle NaN's correctly in floating point comparisons. (Digital Mars C++ does do it correctly.) C++98 doesn't say anything about NaN or Infinity handling in expressions or library functions. So it must be assumed it doesn't work.

To sum up, there's a lot more to supporting NaNs and infinities than having a template that returns a bit pattern. It has to be built in to the compiler's core logic, and it has to permeate all the library code that deals with floating point. And it has to be in the Standard.

To illustrate, if either op1 or op2 or both are NaN, then:

(op1 < op2)

does not yield the same result as:

!(op1 >= op2)

if the NaNs are done correctly.

Why use static if(0) rather than if (0)?

Some limitations are:

  1. if (0) introduces a new scope, static if(...) does not. Why does this matter? It matters if one wants to conditionally declare a new variable:
    static if (...) int x; else long x;
x = 3;
    whereas:
    if (...) int x; else long x;
x = 3;    // error, x is not defined
  2. False static if conditionals don't have to semantically work. For example, it may depend on a conditionally compiled declaration somewhere else:
    static if (...) int x;
int test()
{
    static if (...) return x;
    else return 0;
}
  3. Static if's can appear where only declarations are allowed:
    class Foo
{
    static if (...)
        int x;
}
  4. Static if's can declare new type aliases:
    static if (0 || is(int T)) T x;
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


The D Style - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

The D Style

The D Style is a set of style conventions for writing D programs. The D Style is not enforced by the compiler. It is purely cosmetic and a matter of choice. Adhering to the D Style, however, will make it easier for others to work with your code and easier for you to work with others' code. The D Style can form the starting point for a project style guide customized for your project team.

Submissions to Phobos and other official D source code will follow these guidelines.

Whitespace

  • One statement per line.
  • Use spaces instead of hardware tabs.
  • Each indentation level will be four columns.

Comments

  • Use // comments to document a single line:
    statement;  // comment
statement;  // comment
  • Use block comments to document a multiple line block of statements:
    /* comment
 * comment
 */
 statement;
 statement;
  • Use version (none) to ‘comment out’ a piece of trial code that is syntactically valid:
      version (none)
  {
    /* comment
     * comment
     */
     statement;
     statement;
  }
    It can be turned on with version(all):
      version (all)
  {
    /* comment
     * comment
     */
     statement;
     statement;
  }
  • Use nesting comments to ‘comment out’ a piece of syntactically invalid code:
    /+++++
    /* comment
     * comment
     */
     { statement;
       statement;
 +++++/

Naming Conventions

General
Unless listed otherwise below, names should be camelCased (this includes all variables). So, names formed by joining multiple words have each word other than the first word capitalized. Also, names do not begin with an underscore ‘_’ unless they are private.
int myFunc();
string myLocalVar;
Modules
Module and package names should be all lowercase, and only contain the characters [a..z][0..9][_]. This avoids problems when dealing with case-insensitive file systems.
import std.algorithm;
Classes, Structs, Unions, Enums, Templates
The names of user-defined types should be PascalCased, which is the same as camelCased except that the first letter is uppercase.
class Foo;
struct FooAndBar;
An exception is that eponymous templates that return a value instead of a type should not be capitalized, as they are conceptually more similar to functions.
template GetSomeType(T) { alias T GetSomeType; }
template isSomeType(T) { enum isSomeType = is(T == SomeType); }
Functions
Function names should be camelCased, so their first letter is lowercase. This includes properties and member functions.
int done();
int doneProcessing();
Constants
The names of constants should be camelCased just like normal variables.
enum secondsPerMinute = 60;
immutable hexDigits = "0123456789ABCDEF";
Enum members
The members of enums should be camelCased, so their first letter is lowercase.
Enum Direction { bwd, fwd, both }
Enum OpenRight { no, yes }

Meaningless Type Aliases

Things like:

alias void VOID;
alias int INT;
alias int* pint;

should be avoided.

Declaration Style

Since the declarations are left-associative, left justify them:

int[] x, y; // makes it clear that x and y are the same type
int** p, q; // makes it clear that p and q are the same type

to emphasize their relationship. Do not use the C style:

int []x, y; // confusing since y is also an int[]
int **p, q; // confusing since q is also an int**

Operator Overloading

Operator overloading is a powerful tool to extend the basic types supported by the language. But being powerful, it has great potential for creating obfuscated code. In particular, the existing D operators have conventional meanings, such as ‘+’ means ‘add’ and ‘<<’ means ‘shift left’. Overloading operator ‘+’ with a meaning different from ‘add’ is arbitrarily confusing and should be avoided.

Hungarian Notation

Using hungarian notation to denote the type of a variable is a bad idea. However, using notation to denote the purpose of a variable (that cannot be expressed by its type) is often a good practice.

Properties

Functions should be property functions whenever appropriate. In particular, getters and setters should generally be avoided in favor of property functions. And in general, whereas functions should be verbs, properties should be nouns, just like if they were member variables. Getter properties should not alter state.

Documentation

All public declarations will be documented in Ddoc format.

Unit Tests

As much as practical, all functions will be exercised by unit tests using unittest blocks immediately following the function to be tested. Every path of code should be executed at least once, verified by the code coverage analyzer.

Additional Requirements for Phobos

In general, this guide does not try to recommend or require that code conform to any particular formatting guidelines. The small section on whitespace at the top contains its only formatting guidelines. However, for Phobos and other official D source code, there are two additional requirements:

  • Braces should be on their own line. There are a few exceptions to this (such as when declaring lambda functions), but with any normal function block or type definition, the braces should be on their own line.
    • void func(int param)
{
    if(param < 0)
    {
        ...
    }
    else
    {
        ...
    }
}
  • Lines have a soft limit of 80 characters and a hard limit of 120 characters. This means that most lines of code should be no longer than 80 characters long but that they can exceed 80 characters when appropriate. However, they can never exceed 120 characters.

We are not necessarily recommending that all code follow these two rules. They're both likely to be controversial in any discussion on coding standards. However, they are required in submissions to Phobos and other official D source code.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Glossary - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Glossary

BLIT (Block Transfer)
Also known as BLT, blit refers to copying memory byte for byte. In C, this is referred to as a memcpy operation. The name originated with the BLT instruction on the DEC PDP-10 computer.
CTFE (Compile Time Function Evaluation)
Refers to the ability to execute regular D functions at compile time rather than at run time.
code point
In Unicode terminology, a code point is a logical character. The range of code points is 0 through 0x10FFFF. Only dchars can store code points directly; arrays of char and wchar need to use the variable-length encodings UTF-8 and UTF-16.
COW (Copy On Write)
COW is a memory allocation strategy where arrays are copied if they are to be modified.
Data Race
One thread reading or writing a memory location while another thread is reading or writing that same location.
Functor
An user-defined type (struct or class) that defines the function call operator ( in D) and as such can be used similarly to a function.
GC (Garbage Collection)
Garbage collection is the common name for the term automatic memory management. Memory can be allocated and used, and the GC will automatically free any chunks of memory no longer referred to. In contrast, explicit memory management is where the programmer must carefully match up each allocation with one and only one free.
Higher-order function
A function that either accepts another function as a parameter, returns a function, or both.
IFTI (Implicit Function Template Instantiation)
Refers to the ability to instantiate a template function without having to explicitly pass in the types to the template. Instead, the types are infered automatically from the types of the runtime arguments.
Illegal
A code construct is illegal if it does not conform to the D language specification. This may be true even if the compiler or runtime fails to detect the error.
Input range
A type (i.e., a struct or a class) that defines the member functions empty, head, and next. Input ranges are assumed to be strictly one-pass: there is no way to save the state of the iteration in a copy of the range. See also range.
Implementation Defined Behavior
This is variation in behavior of the D language in a manner that is up to the implementor of the language. An example of implementation defined behavior would be the size in bytes of a pointer: on a 32 bit machine it would be 4 bytes, on a 64 bit machine it would be 8 bytes. Minimizing implementation defined behavior in the language will maximize the portability of code.
NRVO (Named Return Value Optimization)

NRVO is a technique invented by Walter Bright around 1991 (the term for it was coined later) to minimize copying of struct data. Functions normally return their function return values in registers. For structs, however, they often are too big to fit in registers. The usual solution to this is to pass to the function a hidden pointer to a struct instance in the caller's stack frame, and the return value is copied there. For example:

struct S { int a, b, c, d; }

S foo()
{
    S result;
    result.a = 3;
    return result;
}

void test()
{
    S s = foo();
}

is rewritten as:

S* foo(S* hidden)
{
    S result;
    result.a = 3;
    *hidden = result;
    return hidden;
}

void test()
{
    S tmp;
    S s = *foo(&tmp);
}

This rewrite gives us an extra temporary object tmp, and copies the struct contents twice. What NRVO does is recognize that the sole purpose of result is to provide a return value, and so all references to result can be replaced with *hidden. foo is then rewritten as:

S* foo(S* hidden)
{
    hidden.a = 3;
    return hidden;
}

A further optimization is done on the call to foo to eliminate the other copy, giving:

void test()
{
    S s;
    foo(&s);
}

The result is written directly into the destination s, instead of passing through two other instances.

narrow strings
All arrays that use char, wchar, and their qualified versions are narrow strings. (Those include string and wstring). Range-oriented functions in the standard library handle narrow strings specially by automatically decoding the UTF-encoded characters.
opApply
A special member function used to iterate over a collection; this is used by the ForeachStatement.
opApplyReverse
A special member function used to iterate over a collection in the reverse order; this is used by the ForeachStatement.
POD (Plain Old Data)
Refers to a struct that contains no hidden members, does not have virtual functions, does not inherit, has no destructor, and can be initialized and copied via simple bit copies. D structs are POD.
Predicate
A function or delegate returning a Boolean result. Predicates can be nullary (take no arguments), unary (take one argument), binary (take two arguments), or n-ary (take n arguments). Usually predicates are mentioned within the context of higher-order functions, which accept predicates as parameters.
RAII (Resource Acquisition Is Initialization)
RAII refers to the technique of having the destructor of a class object called when the object goes out of scope. The destructor then releases any resources acquired by that object. RAII is commonly used for resources that are in short supply or that must have a predictable point when they are released. RAII objects in D are created using the scope storage class.
Sequential Consistency
Data being written in one order in one thread being visible in the same order to another thread.
SFINAE (Substitution Failure Is Not An Error)
If template argument deduction results in a type that is not valid, that specialization of the template is not considered further. It is not a compile error. See also SFINAE.
TMP (Template Metaprogramming)
TMP is using the template features of the language to execute programs at compile time rather than runtime.
TLS (Thread Local Storage)
TLS allocates each thread its own instance of the global data. See also Wikipedia.
UB (Undefined Behavior)
Undefined behavior happens when an illegal code construct is executed. Undefined behavior can include random, erratic results, crashes, faulting, etc. A buffer overflow is an example of undefined behavior.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


ASCII Table - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

ASCII Table

      00  10  20  30  40  50  60  70

 00  NUL DLE SPC   0   @   P   `   p
 01  SOH DC1   !   1   A   Q   a   q
 02  STX DC2   "   2   B   R   b   r
 03  ETX DC3   #   3   C   S   c   s
 04  EOT DC4   $   4   D   T   d   t
 05  ENQ NAK   %   5   E   U   e   u
 06  ACK SYN   &   6   F   V   f   v
 07  BEL ETB   '   7   G   W   g   w
 08  BS  CAN   (   8   H   X   h   x
 09  TAB EM    )   9   I   Y   i   y
 0A  LF  SUB   *   :   J   Z   j   z
 0B  VT  ESC   +   ;   K   [   k   {
 0C  FF  FS    ,   <   L   \   l   |
 0D  CR  GS    -   =   M   ]   m   }
 0E  SO  RS    .   >   N   ^   n   ~
 0F  SI  US    /   ?   O   _   o DEL
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Acknowledgements - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Acknowledgements

The following (incomplete) list of people have contributed to the D language project; with ideas, code, expertise, marketing, inspiration and moral support.

Andrei Alexandrescu, Kris Bell, Don Clugston, Hauke Duden, Bruce Eckel, Eric Engstrom, Dave Fladebo, David Friedman, Stewart Gordon, Kenji Hara, Christian Hartung, David Held, Ben Hinkle, Kazuhiro Inaba, Jan Knepper, Thomas Kuehne, Helmut Leitner, Lubomir Litchev, Bartosz Milewski, Christopher E. Miller, Pavel Minayev, Antonio Monteiro, Paul Nash, Pat Nelson, Derek Parnell, Burton Radons, Tim Rentsch, Fabio Riccardi, Brad Roberts, Bob Taniguchi, Bob W, John Whited, Matthew Wilson, Peter Zatloukal

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Lexical - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Lexical

The lexical analysis is independent of the syntax parsing and the semantic analysis. The lexical analyzer splits the source text up into tokens. The lexical grammar describes what those tokens are. The grammar is designed to be suitable for high speed scanning, it has a minimum of special case rules, there is only one phase of translation, and to make it easy to write a correct scanner for. The tokens are readily recognizable by those familiar with C and C++.

Source Text

D source text can be in one of the following formats:
  • ASCII
  • UTF-8
  • UTF-16BE
  • UTF-16LE
  • UTF-32BE
  • UTF-32LE
UTF-8 is a superset of traditional 7-bit ASCII. One of the following UTF BOMs (Byte Order Marks) can be present at the beginning of the source text:

UTF Byte Order Marks
Format | BOM
UTF-8 | EF BB BF
UTF-16BE | FE FF
UTF-16LE | FF FE
UTF-32BE | 00 00 FE FF
UTF-32LE | FF FE 00 00
ASCII | no BOM

If the source file does not start with a BOM, then the first character must be less than or equal to U0000007F.

There are no digraphs or trigraphs in D.

The source text is decoded from its source representation into Unicode Characters. The Characters are further divided into: WhiteSpace, EndOfLine, Comments, SpecialTokenSequences, Tokens, all followed by EndOfFile.

The source text is split into tokens using the maximal munch technique, i.e., the lexical analyzer tries to make the longest token it can. For example >> is a right shift token, not two greater than tokens. An exception to this rule is that a .. embedded inside what looks like two floating point literals, as in 1..2, is interpreted as if the .. was separated by a space from the first integer.

Character Set

Character
    any Unicode character

End of File

EndOfFile:
    physical end of the file
    \u0000
    \u001A
The source text is terminated by whichever comes first.

End of Line

EndOfLine:
    \u000D
    \u000A
    \u000D \u000A
    \u2028
    \u2029
    EndOfFile
There is no backslash line splicing, nor are there any limits on the length of a line.

White Space

WhiteSpace:
    Space
    Space WhiteSpace

Space:
    \u0020
    \u0009
    \u000B
    \u000C

Comments

Comment:
    BlockComment
    LineComment
    NestingBlockComment

BlockComment
    /* Characters */

LineComment
    // Characters EndOfLine

NestingBlockComment:
    /+ NestingBlockCommentCharacters +/

NestingBlockCommentCharacters:
    NestingBlockCommentCharacter
    NestingBlockCommentCharacter NestingBlockCommentCharacters

NestingBlockCommentCharacter:
    Character
    NestingBlockComment

Characters:
    Character
    Character Characters

D has three kinds of comments:

  1. Block comments can span multiple lines, but do not nest.
  2. Line comments terminate at the end of the line.
  3. Nesting block comments can span multiple lines and can nest.

The contents of strings and comments are not tokenized. Consequently, comment openings occurring within a string do not begin a comment, and string delimiters within a comment do not affect the recognition of comment closings and nested "/+" comment openings. With the exception of "/+" occurring within a "/+" comment, comment openings within a comment are ignored.

a = /+ // +/ 1;    // parses as if 'a = 1;'
a = /+ "+/" +/ 1"; // parses as if 'a = " +/ 1";'
a = /+ /* +/ */ 3; // parses as if 'a = */ 3;'
Comments cannot be used as token concatenators, for example, abc/**/def is two tokens, abc and def, not one abcdef token.

Tokens

Token:
    Identifier
    StringLiteral
    CharacterLiteral
    IntegerLiteral
    FloatLiteral
    Keyword
    /
    /=
    .
    ..
    ...
    &
    &=
    &&
    |
    |=
    ||
    -
    -=
    --
    +
    +=
    ++
    <
    <=
    <<
    <<=
    <>
    <>=
    >
    >=
    >>=
    >>>=
    >>
    >>>
    !
    !=
    !<>
    !<>=
    !<
    !<=
    !>
    !>=
    (
    )
    [
    ]
    {
    }
    ?
    ,
    ;
    :
    $
    =
    ==
    *
    *=
    %
    %=
    ^
    ^=
    ^^
    ^^=
    ~
    ~=
    @
    =>
    #

Identifiers

Identifier:
    IdentifierStart
    IdentifierStart IdentifierChars

IdentifierChars:
    IdentifierChar
    IdentifierChar IdentifierChars

IdentifierStart:
    _
    Letter
    UniversalAlpha

IdentifierChar:
    IdentifierStart
    0
    NonZeroDigit
Identifiers start with a letter, _, or universal alpha, and are followed by any number of letters, _, digits, or universal alphas. Universal alphas are as defined in ISO/IEC 9899:1999(E) Appendix D. (This is the C99 Standard.) Identifiers can be arbitrarily long, and are case sensitive. Identifiers starting with __ (two underscores) are reserved.

String Literals

StringLiteral:
    WysiwygString
    AlternateWysiwygString
    DoubleQuotedString

    HexString
   DelimitedString
    TokenString

WysiwygString:
    r" WysiwygCharacters " StringPostfixopt

AlternateWysiwygString:
    ` WysiwygCharacters ` StringPostfixopt

WysiwygCharacters:
    WysiwygCharacter
    WysiwygCharacter WysiwygCharacters

WysiwygCharacter:
    Character
    EndOfLine

DoubleQuotedString:
    " DoubleQuotedCharacters " StringPostfixopt

DoubleQuotedCharacters:
    DoubleQuotedCharacter
    DoubleQuotedCharacter DoubleQuotedCharacters

DoubleQuotedCharacter:
    Character
    EscapeSequence
    EndOfLine

EscapeSequence:
    \'
    \"
    \?
    \\
    \a
    \b
    \f
    \n
    \r
    \t
    \v
    \ EndOfFile
    \x HexDigit HexDigit
    \ OctalDigit
    \ OctalDigit OctalDigit
    \ OctalDigit OctalDigit OctalDigit
    \u HexDigit HexDigit HexDigit HexDigit
    \U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit
    \ NamedCharacterEntity

HexString:
    x" HexStringChars " StringPostfixopt

HexStringChars:
    HexStringChar
    HexStringChar HexStringChars

HexStringChar:
    HexDigit
    WhiteSpace
    EndOfLine

StringPostfix:
    c
    w
    d

DelimitedString:
    q" Delimiter WysiwygCharacters MatchingDelimiter "

TokenString:
    q{ Tokens }

A string literal is either a double quoted string, a wysiwyg quoted string, an escape sequence, a delimited string, a token string, or a hex string.

In all string literal forms, an EndOfLine is regarded as a single \n character.

Wysiwyg Strings

Wysiwyg "what you see is what you get" quoted strings are enclosed by r" and ". All characters between the r" and " are part of the string. There are no escape sequences inside r" ":

r"hello"
r"c:\root\foo.exe"
r"ab\n" // string is 4 characters,
        // 'a', 'b', '\', 'n'

An alternate form of wysiwyg strings are enclosed by backquotes, the ` character. The ` character is not available on some keyboards and the font rendering of it is sometimes indistinguishable from the regular ' character. Since, however, the ` is rarely used, it is useful to delineate strings with " in them.

`hello`
`c:\root\foo.exe`
`ab\n`  // string is 4 characters,
        // 'a', 'b', '\', 'n'

Double Quoted Strings

Double quoted strings are enclosed by "". Escape sequences can be embedded into them with the typical \ notation.
"hello"
"c:\\root\\foo.exe"
"ab\n"   // string is 3 characters,
         // 'a', 'b', and a linefeed
"ab
"        // string is 3 characters,
         // 'a', 'b', and a linefeed

Hex Strings

Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters.

x"0A"              // same as "\x0A"
x"00 FBCD 32FD 0A" // same as
               // "\x00\xFB\xCD\x32\xFD\x0A"
Whitespace and newlines are ignored, so the hex data can be easily formatted. The number of hex characters must be a multiple of 2.

Adjacent strings are concatenated with the ~ operator, or by simple juxtaposition:

"hello " ~ "world" ~ "\n" // forms the string
       // 'h','e','l','l','o',' ',
       // 'w','o','r','l','d',linefeed
The following are all equivalent:
"ab" "c"
r"ab" r"c"
r"a" "bc"
"a" ~ "b" ~ "c"

The optional StringPostfix character gives a specific type to the string, rather than it being inferred from the context. This is useful when the type cannot be unambiguously inferred, such as when overloading based on string type. The types corresponding to the postfix characters are:

String Literal Postfix Characters
Postfix | Type | Aka
c | immutable(char)[] | string
w | immutable(wchar)[] | wstring
d | immutable(dchar)[] | dstring
"hello"c  // string
"hello"w  // wstring
"hello"d  // dstring

The string literals are assembled as UTF-8 char arrays, and the postfix is applied to convert to wchar or dchar as necessary as a final step.

String literals are read only. Writes to string literals cannot always be detected, but cause undefined behavior.

Delimited Strings

Delimited strings use various forms of delimiters. The delimiter, whether a character or identifer, must immediately follow the " without any intervening whitespace. The terminating delimiter must immediately precede the closing " without any intervening whitespace. A nesting delimiter nests, and is one of the following characters:

Nesting Delimiters
Delimiter | Matching Delimiter
[ | ]
( | )
< | >
{ | }
q"(foo(xxx))"   // "foo(xxx)"
q"[foo{]"       // "foo{"

If the delimiter is an identifier, the identifier must be immediately followed by a newline, and the matching delimiter is the same identifier starting at the beginning of the line:

writefln(q"EOS
This
is a multi-line
heredoc string
EOS"
);

The newline following the opening identifier is not part of the string, but the last newline before the closing identifier is part of the string. The closing identifier must be placed on its own line at the leftmost column.

Otherwise, the matching delimiter is the same as the delimiter character:

q"/foo]/"       // "foo]"
q"/abc/def/"    // error

Token Strings

Token strings open with the characters q{ and close with the token }. In between must be valid D tokens. The { and } tokens nest. The string is formed of all the characters between the opening and closing of the token string, including comments.

q{foo}              // "foo"
q{/*}*/ }           // "/*}*/ "
q{ foo(q{hello}); } // " foo(q{hello}); "
q{ __TIME__ }       // " __TIME__ ", i.e. it is not replaced with the time
q{ __EOF__ }        // error, as __EOF__ is not a token, it's end of file

Character Literals

CharacterLiteral:
    ' SingleQuotedCharacter '

SingleQuotedCharacter:
    Character
    EscapeSequence
Character literals are a single character or escape sequence enclosed by single quotes, ' '.

Integer Literals

IntegerLiteral:
    Integer
    Integer IntegerSuffix

Integer:
    DecimalInteger
    BinaryInteger
    HexadecimalInteger

IntegerSuffix:
    L
    u
    U
    Lu
    LU
    uL
    UL

DecimalInteger:
    0
    NonZeroDigit
    NonZeroDigit DecimalDigitsUS

BinaryInteger:
    BinPrefix BinaryDigits

BinPrefix:
    0b
    0B

HexadecimalInteger:
    HexPrefix HexDigitsNoSingleUS

NonZeroDigit:
    1
    2
    3
    4
    5
    6
    7
    8
    9

DecimalDigits:
    DecimalDigit
    DecimalDigit DecimalDigits

DecimalDigitsUS:
    DecimalDigitUS
    DecimalDigitUS DecimalDigitsUS

DecimalDigitsNoSingleUS:
    DecimalDigit
    DecimalDigit DecimalDigitsUS
    DecimalDigitsUS DecimalDigit

DecimalDigitsNoStartingUS:
    DecimalDigit
    DecimalDigit DecimalDigitsUS

DecimalDigit:
    0
    NonZeroDigit

DecimalDigitUS:
    DecimalDigit
    _

BinaryDigitsUS:
    BinaryDigitUS
    BinaryDigitUS BinaryDigitsUS

BinaryDigit:
    0
    1

BinaryDigitUS:
    BinaryDigit
    _

OctalDigits:
    OctalDigit
    OctalDigit OctalDigits

OctalDigitsUS:
    OctalDigitUS
    OctalDigitUS OctalDigitsUS

OctalDigit:
    0
    1
    2
    3
    4
    5
    6
    7

OctalDigitUS:
    OctalDigit
    _

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigitsUS:
    HexDigitUS
    HexDigitUS HexDigitsUS

HexDigitsNoSingleUS:
    HexDigit
    HexDigit HexDigitsUS
    HexDigitsUS HexDigit

HexDigit:
    DecimalDigit
    HexLetter

HexLetter:
    a
    b
    c
    d
    e
    f
    A
    B
    C
    D
    E
    F
    _

Integers can be specified in decimal, binary, octal, or hexadecimal.

Decimal integers are a sequence of decimal digits.

Binary integers are a sequence of binary digits preceded by a ‘0b’.

C-style octal integer notation was deemed too easy to mix up with decimal notation. The above is only fully supported in string literals. D still supports octal integer literals interpreted at compile time through the std.conv.octal template, as in octal!167.

Hexadecimal integers are a sequence of hexadecimal digits preceded by a ‘0x’.

Integers can have embedded ‘_’ characters, which are ignored. The embedded ‘_’ are useful for formatting long literals, such as using them as a thousands separator:

123_456       // 123456
1_2_3_4_5_6_  // 123456

Integers can be immediately followed by one ‘L’ or one of ‘u’ or ‘U’ or both. Note that there is no ‘l’ suffix.

The type of the integer is resolved as follows:

Decimal Literal Types
Decimal Literal | Type
0 .. 2_147_483_647 | int
2_147_483_648 .. 9_223_372_036_854_775_807L | long
Decimal Literal, L Suffix | Type
0L .. 9_223_372_036_854_775_807L | long
Decimal Literal, U Suffix | Type
0U .. 4_294_967_296U | uint
4_294_967_296U .. 18_446_744_073_709_551_615UL | ulong
Decimal Literal, UL Suffix | Type
0UL .. 18_446_744_073_709_551_615UL | ulong
Non-Decimal Literal | Type
0x0 .. 0x7FFF_FFFF | int
0x8000_0000 .. 0xFFFF_FFFF | uint
0x1_0000_0000 .. 0x7FFF_FFFF_FFFF_FFFF | long
0x8000_0000_0000_0000 .. 0xFFFF_FFFF_FFFF_FFFF | ulong
Non-Decimal Literal, L Suffix | Type
0x0L .. 0x7FFF_FFFF_FFFF_FFFFL | long
0x8000_0000_0000_0000L .. 0xFFFF_FFFF_FFFF_FFFFL | ulong
Non-Decimal Literal, U Suffix | Type
0x0U .. 0xFFFF_FFFFU | uint
0x1_0000_0000UL .. 0xFFFF_FFFF_FFFF_FFFFUL | ulong
Non-Decimal Literal, UL Suffix | Type
0x0UL .. 0xFFFF_FFFF_FFFF_FFFFUL | ulong

Floating Literals

FloatLiteral:
    Float
    Float Suffix
    Integer ImaginarySuffix
    Integer FloatSuffix ImaginarySuffix
    Integer RealSuffix ImaginarySuffix

Float:
    DecimalFloat
    HexFloat

DecimalFloat:
    LeadingDecimal .
    LeadingDecimal . DecimalDigits
    DecimalDigits . DecimalDigitsNoSingleUS DecimalExponent
    . DecimalInteger
    . DecimalInteger DecimalExponent
    LeadingDecimal DecimalExponent

DecimalExponent
    DecimalExponentStart DecimalDigitsNoSingleUS

DecimalExponentStart
    e
    E
    e+
    E+
    e-
    E-

HexFloat:
    HexPrefix HexDigitsNoSingleUS . HexDigitsNoSingleUS HexExponent
    HexPrefix . HexDigitsNoSingleUS HexExponent
    HexPrefix HexDigitsNoSingleUS HexExponent

HexPrefix:
    0x
    0X

HexExponent:
    HexExponentStart DecimalDigitsNoSingleUS

HexExponentStart:
    p
    P
    p+
    P+
    p-
    P-

Suffix:
    FloatSuffix
    RealSuffix
    ImaginarySuffix
    FloatSuffix ImaginarySuffix
    RealSuffix ImaginarySuffix

FloatSuffix:
    f
    F

RealSuffix:
    L

ImaginarySuffix:
    i

LeadingDecimal:
    DecimalInteger
    0 DecimalDigitsNoSingleUS

Floats can be in decimal or hexadecimal format.

Hexadecimal floats are preceded with a 0x and the exponent is a p or P followed by a decimal number serving as the exponent of 2.

Floating literals can have embedded ‘_’ characters, which are ignored. The embedded ‘_’ are useful for formatting long literals to make them more readable, such as using them as a thousands separator:

123_456.567_8         // 123456.5678
1_2_3_4_5_6_._5_6_7_8 // 123456.5678
1_2_3_4_5_6_._5e-6_   // 123456.5e-6

Floating literals with no suffix are of type double. Floats can be followed by one f, F, or L suffix. The f or F suffix means it is a float, and L means it is a real.

If a floating literal is followed by i, then it is an ireal (imaginary) type.

Examples:

0x1.FFFFFFFFFFFFFp1023 // double.max
0x1p-52                // double.epsilon
1.175494351e-38F       // float.min
6.3i                   // idouble 6.3
6.3fi                  // ifloat 6.3
6.3Li                  // ireal 6.3

It is an error if the literal exceeds the range of the type. It is not an error if the literal is rounded to fit into the significant digits of the type.

Complex literals are not tokens, but are assembled from real and imaginary expressions during semantic analysis:

4.5 + 6.2i  // complex number (phased out)

Keywords

Keywords are reserved identifiers.
Keyword:
    abstract
    alias
    align
    asm
    assert
    auto

    body
    bool
    break
    byte

    case
    cast
    catch
    cdouble
    cent
    cfloat
    char
    class
    const
    continue
    creal

    dchar
    debug
    default
    delegate
    delete
    deprecated
    do
    double

    else
    enum
    export
    extern

    false
    final
    finally
    float
    for
    foreach
    foreach_reverse
    function

    goto

    idouble
    if
    ifloat
   immutable
    import
    in
    inout
    int
    interface
    invariant
    ireal
    is

    lazy
    long

    macro
    mixin
    module

    new
   nothrow
    null

    out
    override

    package
    pragma
    private
    protected
    public
   pure

    real
    ref
    return

    scope
   shared
    short
    static
    struct
    super
    switch
    synchronized

    template
    this
    throw
    true
    try
    typedef
    typeid
    typeof

    ubyte
    ucent
    uint
    ulong
    union
    unittest
    ushort

    version
    void
    volatile

    wchar
    while
    with

   __FILE__
    __LINE__
    __gshared
    __traits
    __vector
    __parameters

Special Tokens

These tokens are replaced with other tokens according to the following table:

Special Tokens
Special Token | Replaced with...
__DATE__ | string literal of the date of compilation "mmm dd yyyy"
__EOF__ | sets the scanner to the end of the file
__TIME__ | string literal of the time of compilation "hh:mm:ss"
__TIMESTAMP__ | string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
__VENDOR__ | Compiler vendor string, such as "Digital Mars D"
__VERSION__ | Compiler version as an integer, such as 2001

Special Token Sequences

SpecialTokenSequence:
    # line IntegerLiteral EndOfLine
    # line IntegerLiteral Filespec EndOfLine

Filespec:
    " Characters "

Special token sequences are processed by the lexical analyzer, may appear between any other tokens, and do not affect the syntax parsing.

There is currently only one special token sequence, #line.

This sets the source line number to IntegerLiteral, and optionally the source file name to Filespec, beginning with the next line of source text. The source file and line number is used for printing error messages and for mapping generated code back to the source for the symbolic debugging output.

For example:

int #line 6 "foo\bar"
x;  // this is now line 6 of file foo\bar

Note that the backslash character is not treated specially inside Filespec strings.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Modules - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Modules

Module:
    ModuleDeclaration DeclDefs
    DeclDefs

DeclDefs:
    DeclDef
    DeclDef DeclDefs

DeclDef:
    AttributeSpecifier
    ImportDeclaration
    EnumDeclaration
    ClassDeclaration
    InterfaceDeclaration
    AggregateDeclaration
    Declaration
    Constructor
    Destructor
    UnitTest
    StaticConstructor
    StaticDestructor
    SharedStaticConstructor
    SharedStaticDestructor
    ConditionalDeclaration
    DebugSpecification
    VersionSpecification
    StaticAssert
    TemplateDeclaration
    TemplateMixinDeclaration
    TemplateMixin
    MixinDeclaration
    ;

Modules have a one-to-one correspondence with source files. The module name is the file name with the path and extension stripped off.

Modules automatically provide a namespace scope for their contents. Modules superficially resemble classes, but differ in that:

  • There's only one instance of each module, and it is statically allocated.
  • There is no virtual table.
  • Modules do not inherit, they have no super modules, etc.
  • Only one module per file.
  • Module symbols can be imported.
  • Modules are always compiled at global scope, and are unaffected by surrounding attributes or other modifiers.

Modules can be grouped together in hierarchies called packages.

Modules offer several guarantees:

  • The order in which modules are imported does not affect the semantics.
  • The semantics of a module are not affected by what imports it.
  • If a module C imports modules A and B, any modifications to B will not silently change code in C that is dependent on A.

Module Declaration

The ModuleDeclaration sets the name of the module and what package it belongs to. If absent, the module name is taken to be the same name (stripped of path and extension) of the source file name.

ModuleDeclaration:
    module ModuleFullyQualifiedName ;

ModuleFullyQualifiedName:
    ModuleName
    Packages . ModuleName

ModuleName:
    Identifier

Packages:
    PackageName
    Packages . PackageName

PackageName:
    Identifier

The Identifiers preceding the rightmost are the Packages that the module is in. The packages correspond to directory names in the source file path. Package names cannot be keywords, hence the corresponding directory names cannot be keywords, either.

If present, the ModuleDeclaration appears syntactically first in the source file, and there can be only one per source file.

Example:

module c.stdio;    // this is module stdio in the c package

By convention, package and module names are all lower case. This is because those names have a one-to-one correspondence with the operating system's directory and file names, and many file systems are not case sensitive. All lower case package and module names will minimize problems moving projects between dissimilar file systems.

If the file name of a module is an invalid module name (e.g. foo-bar.d), you may use a module declaration to set a valid module name:

module foo_bar;

Import Declaration

Symbols from one module are made available in another module by using the ImportDeclaration:

ImportDeclaration:
    import ImportList ;
    static import ImportList ;

ImportList:
    Import
    ImportBindings
    Import , ImportList

Import:
    ModuleFullyQualifiedName
    ModuleAliasIdentifier = ModuleFullyQualifiedName

ImportBindings:
    Import : ImportBindList

ImportBindList:
    ImportBind
    ImportBind , ImportBindList

ImportBind:
    Identifier
    Identifier = Identifier

ModuleAliasIdentifier:
    Identifier

There are several forms of the ImportDeclaration, from generalized to fine-grained importing.

The order in which ImportDeclarations occur has no significance.

ModuleFullyQualifiedNames in the ImportDeclaration must be fully qualified with whatever packages they are in. They are not considered to be relative to the module that imports them.

Basic Imports

The simplest form of importing is to just list the modules being imported:

import std.stdio; // import module stdio from the std package
import foo, bar;  // import modules foo and bar

void main()
{
    writefln("hello!\n");  // calls std.stdio.writefln
}

How basic imports work is that first a name is searched for in the current namespace. If it is not found, then it is looked for in the imports. If it is found uniquely among the imports, then that is used. If it is in more than one import, an error occurs.

module A;
void foo();
void bar();

module B;
void foo();
void bar();

module C;
import A;
void foo();
void test()
{ foo(); // C.foo() is called, it is found before imports are searched
  bar(); // A.bar() is called, since imports are searched
}

module D;
import A;
import B;
void test()
{ foo();   // error, A.foo() or B.foo() ?
  A.foo(); // ok, call A.foo()
  B.foo(); // ok, call B.foo()
}

module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo();   // call B.foo()
  A.foo(); // call A.foo()
  B.foo(); // call B.foo()
}

Public Imports

By default, imports are private. This means that if module A imports module B, and module B imports module C, then C's names are not searched for. An import can be specifically declared public, when it will be treated as if any imports of the module with the ImportDeclaration also import the public imported modules.

All symbols from a publicly imported module are also aliased in the importing module. This means that if module D imports module C, and module C publicly imports module B which has the symbol bar, in module D you can access the symbol via bar, B.bar, and C.bar.

module A;
void foo() { }

module B;
void bar() { }

module C;
import A;
public import B;
...
foo();	// call  A.foo()
bar();	// calls B.bar()

module D;
import C;
...
foo();	 // error, foo() is undefined
bar();	 // ok, calls B.bar()
B.bar(); // ditto
C.bar(); // ok, calls C.bar() which is an alias to B.bar()

Static Imports

Basic imports work well for programs with relatively few modules and imports. If there are a lot of imports, name collisions can start occurring between the names in the various imported modules. One way to stop this is by using static imports. A static import requires one to use a fully qualified name to reference the module's names:

static import std.stdio;

void main()
{
 writefln("hello!");           // error, writefln is undefined
 std.stdio.writefln("hello!"); // ok, writefln is fully qualified
}

Renamed Imports

A local name for an import can be given, through which all references to the module's symbols must be qualified with:

import io = std.stdio;

void main()
{
 io.writefln("hello!");        // ok, calls std.stdio.writefln
 std.stdio.writefln("hello!"); // error, std is undefined
 writefln("hello!");           // error, writefln is undefined
}

Renamed imports are handy when dealing with very long import names.

Selective Imports

Specific symbols can be exclusively imported from a module and bound into the current namespace:

import std.stdio : writefln, foo = writef;

void main()
{
 std.stdio.writefln("hello!"); // error, std is undefined
 writefln("hello!");           // ok, writefln bound into current namespace
 writef("world");              // error, writef is undefined
 foo("world");                 // ok, calls std.stdio.writef()
 fwritefln(stdout, "abc");     // error, fwritefln undefined
}

static cannot be used with selective imports.

Renamed and Selective Imports

When renaming and selective importing are combined:

import io = std.stdio : foo = writefln;

void main()
{
 writefln("bar");           // error, writefln is undefined
 std.stdio.foo("bar");      // error, foo is bound into current namespace
 std.stdio.writefln("bar"); // error, std is undefined
 foo("bar");                // ok, foo is bound into current namespace,
                            // FQN not required
 io.writefln("bar");        // ok, io=std.stdio bound the name io in
                            // the current namespace to refer to the entire module
 io.foo("bar");             // error, foo is bound into current namespace,
                            // foo is not a member of io

Scoped Imports

Import declarations may be used at any scope. For example:

void main() {
  import std.stdio;
  writeln("bar");
}

The imports are looked up to satisfy any unresolved symbols at that scope. Imported symbols may hide symbols from outer scopes.

In function scopes, imported symbols only become visible after the import declaration lexically appears in the function body. In other words, imported symbols at function scope cannot be forward referenced.

void main() {
  void writeln(string) {}
  void foo() {
    writeln("bar"); // calls main.writeln
    import std.stdio;
    writeln("bar"); // calls std.stdio.writeln
    void writeln(string) {}
    writeln("bar"); // calls main.foo.writeln
  }
  writeln("bar"); // calls main.writeln
  std.stdio.writeln("bar");  // error, std is undefined
}

Module Scope Operator

Sometimes, it's necessary to override the usual lexical scoping rules to access a name hidden by a local name. This is done with the global scope operator, which is a leading ‘.’:
int x;

int foo(int x)
{
 if (y)
   return x;  // returns foo.x, not global x
 else
   return .x; // returns global x
}
The leading ‘.’ means look up the name at the module scope level.

Static Construction and Destruction

Static constructors are code that gets executed to initialize a module or a class before the main() function gets called. Static destructors are code that gets executed after the main() function returns, and are normally used for releasing system resources.

There can be multiple static constructors and static destructors within one module. The static constructors are run in lexical order, the static destructors are run in reverse lexical order.

Static constructors and static destructors run on thread local data, and are run whenever threads are created or destroyed.

Shared static constructors and shared static destructors are run on global shared data, and constructors are run once on program startup and destructors are run once on program termination.

Order of Static Construction

Shared static constructors on all modules are run before any static constructors.

The order of static initialization is implicitly determined by the import declarations in each module. Each module is assumed to depend on any imported modules being statically constructed first. Other than following that rule, there is no imposed order on executing the module static constructors.

Cycles (circular dependencies) in the import declarations are allowed as long as not both of the modules contain static constructors or static destructors. Violation of this rule will result in a runtime exception.

Order of Static Construction within a Module

Within a module, the static construction occurs in the lexical order in which they appear.

Order of Static Destruction

It is defined to be exactly the reverse order that static construction was performed in. Static destructors for individual modules will only be run if the corresponding static constructor successfully completed.

Shared static destructors are executed after static destructors.

Order of Unit tests

Unit tests are run in the lexical order in which they appear within a module.

Mixin Declaration

MixinDeclaration:
    mixin ( AssignExpression ) ;

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid DeclDefs, and is compiled as such.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Declarations - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Declarations

Declaration:
    AliasDeclaration
    AliasThisDeclaration
    Decl

AliasDeclaration:
    alias BasicType Declarator
    alias AliasInitializerList

AliasInitializerList:
    AliasInitializer
    AliasInitializer , AliasInitializerList

AliasInitializer:
    Identifier = Type

AliasThisDeclaration:
    alias Identifier this
    alias this = Identifier

Decl:
    StorageClasses Decl
    BasicType Declarators ;
    BasicType Declarator FunctionBody
    AutoDeclaration

Declarators:
    DeclaratorInitializer
    DeclaratorInitializer , DeclaratorIdentifierList

DeclaratorInitializer:
    Declarator
    Declarator = Initializer

DeclaratorIdentifierList:
    DeclaratorIdentifier
    DeclaratorIdentifier , DeclaratorIdentifierList

DeclaratorIdentifier:
    Identifier
    Identifier = Initializer

BasicType:
    BasicTypeX
    .IdentifierList
    IdentifierList
    Typeof
    Typeof . IdentifierList
    const( Type )
    immutable( Type )
    shared( Type )
    inout( Type )

BasicTypeX:
    bool
    byte
    ubyte
    short
    ushort
    int
    uint
    long
    ulong
    char
    wchar
    dchar
    float
    double
    real
    ifloat
    idouble
    ireal
    cfloat
    cdouble
    creal
    void

BasicType2:
    *
    [ ]
    [ AssignExpression ]
    [ AssignExpression .. AssignExpression ]
    [ Type ]
    delegate Parameters MemberFunctionAttributesopt
    function Parameters FunctionAttributesopt

Declarator:
    BasicType2opt ( Declarator ) DeclaratorSuffixesopt
    BasicType2opt Identifier DeclaratorSuffixesopt

DeclaratorSuffixes:
    DeclaratorSuffix
    DeclaratorSuffix DeclaratorSuffixes

DeclaratorSuffix:
    [ ]
    [ AssignExpression ]
    [ Type ]
    TemplateParameterListopt Parameters MemberFunctionAttributesopt Constraintopt

IdentifierList:
    Identifier
    Identifier . IdentifierList
    TemplateInstance
    TemplateInstance . IdentifierList

StorageClasses:
    StorageClass
    StorageClass StorageClasses

StorageClass:
    abstract
    auto
    TypeCtor
    deprecated
    enum
    extern
    final
    nothrow
    override
    pure
    __gshared
    Property
    scope
    static
    synchronized

Property:
    @ PropertyIdentifier

PropertyIdentifier:
    property
    safe
    trusted
    system
    disable

TypeCtors:
    TypeCtor
    TypeCtor TypeCtors

TypeCtor:
    const
    immutable
    inout
    shared

Type:
    TypeCtorsopt BasicType
    TypeCtorsopt BasicType Declarator2

Declarator2:
    BasicType2opt DeclaratorSuffixesopt
    BasicType2opt ( Declarator2 ) DeclaratorSuffixesopt

Parameters:
    ( ParameterList )
    ( )

ParameterList:
    Parameter
    Parameter , ParameterList
    ...

Parameter:
    InOutopt BasicType Declarator
    InOutopt BasicType Declarator ...
    InOutopt BasicType Declarator = DefaultInitializerExpression
    InOutopt Type
    InOutopt Type ...

InOut:
    InOutX
    InOut InOutX

InOutX:
    auto
    TypeCtor
    final
    in
    lazy
    out
    ref
    scope

FunctionAttributes:
    FunctionAttribute
    FunctionAttribute FunctionAttributes

FunctionAttribute:
    nothrow
    pure
    Property

MemberFunctionAttributes:
    MemberFunctionAttribute
    MemberFunctionAttribute MemberFunctionAttributes

MemberFunctionAttribute:
    const
    immutable
    inout
    shared
    FunctionAttribute

DefaultInitializerExpression:
    AssignExpression
    __FILE__
    __LINE__

Initializer:
    VoidInitializer
    NonVoidInitializer

NonVoidInitializer:
    AssignExpression
    ArrayInitializer
    StructInitializer

ArrayInitializer:
    [ ]
    [ ArrayMemberInitializations ]

ArrayMemberInitializations:
    ArrayMemberInitialization
    ArrayMemberInitialization ,
    ArrayMemberInitialization , ArrayMemberInitializations

ArrayMemberInitialization:
    NonVoidInitializer
    AssignExpression : NonVoidInitializer

StructInitializer:
    {  }
    { StructMemberInitializers }

StructMemberInitializers:
    StructMemberInitializer
    StructMemberInitializer ,
    StructMemberInitializer , StructMemberInitializers

StructMemberInitializer:
    NonVoidInitializer
    Identifier : NonVoidInitializer

Declaration Syntax

Declaration syntax generally reads right to left:

int x;    // x is an int
int* x;   // x is a pointer to int
int** x;  // x is a pointer to a pointer to int
int[] x;  // x is an array of ints
int*[] x; // x is an array of pointers to ints
int[]* x; // x is a pointer to an array of ints

Arrays read right to left as well:

int[3] x;     // x is an array of 3 ints
int[3][5] x;  // x is an array of 5 arrays of 3 ints
int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints

Pointers to functions are declared using the function keyword:

int function(char) x; // x is a pointer to
                     // a function taking a char argument
                     // and returning an int
int function(char)[] x; // x is an array of
                     // pointers to functions
                     // taking a char argument
                     // and returning an int

C-style array, function pointer and pointer to array declarations are deprecated:

int x[3];          // x is an array of 3 ints
int x[3][5];       // x is an array of 3 arrays of 5 ints
int (*x[5])[3];    // x is an array of 5 pointers to arrays of 3 ints
int (*x)(char);    // x is a pointer to a function taking a char argument
                   // and returning an int
int (*[] x)(char); // x is an array of pointers to functions
                   // taking a char argument and returning an int

In a declaration declaring multiple symbols, all the declarations must be of the same type:

int x,y;   // x and y are ints
int* x,y;  // x and y are pointers to ints
int x,*y;  // error, multiple types
int[] x,y; // x and y are arrays of ints
int x[],y; // error, multiple types

Implicit Type Inference

AutoDeclaration:
    StorageClasses AutoDeclarationX ;

AutoDeclarationX:
    Identifier = Initializer
    AutoDeclarationX , Identifier = Initializer

If a declaration starts with a StorageClass and has a NonVoidInitializer from which the type can be inferred, the type on the declaration can be omitted.

static x = 3;      // x is type int
auto y = 4u;       // y is type uint
auto s = "string"; // s is type immutable(char)[]

class C { ... }

auto c = new C();  // c is a handle to an instance of class C

The NonVoidInitializer cannot contain forward references (this restriction may be removed in the future). The implicitly inferred type is statically bound to the declaration at compile time, not run time.

An ArrayLiteral is inferred to be a dynamic array type rather than a static array:

auto v = ["hello", "world"]; // type is string[], not string[2]

Type Aliasing

AliasDeclarations create a symbol that is an alias for another type, and can be used anywhere that other type may appear.

alias abc.Foo.bar myint;

Aliased types are semantically identical to the types they are aliased to. The debugger cannot distinguish between them, and there is no difference as far as function overloading is concerned. For example:

alias int myint;

void foo(int x) { . }
void foo(myint m) { . } // error, multiply defined function foo

Alias Declarations

A symbol can be declared as an alias of another symbol. For example:

import string;

alias string.strlen mylen;
 ...
int len = mylen("hello"); // actually calls string.strlen()

The following alias declarations are valid:

template Foo2(T) { alias T t; }
alias Foo2!(int) t1;
alias Foo2!(int).t t2;
alias t1.t t3;
alias t2 t4;

t1.t v1;  // v1 is type int
t2 v2;    // v2 is type int
t3 v3;    // v3 is type int
t4 v4;    // v4 is type int

Aliased symbols are useful as a shorthand for a long qualified symbol name, or as a way to redirect references from one symbol to another:

version (Win32)
{
    alias win32.foo myfoo;
}
version (linux)
{
    alias linux.bar myfoo;
}

Aliasing can be used to ‘import’ a symbol from an import into the current scope:

alias string.strlen strlen;

Aliases can also ‘import’ a set of overloaded functions, that can be overloaded with functions in the current scope:

class A {
    int foo(int a) { return 1; }
}

class B : A {
    int foo( int a, uint b ) { return 2; }
}

class C : B {
    int foo( int a ) { return 3; }
    alias B.foo foo;
}

class D : C  {
}

void test()
{
    D b = new D();
    int i;

    i = b.foo(1, 2u);   // calls B.foo
    i = b.foo(1);       // calls C.foo
}

Note: Type aliases can sometimes look indistinguishable from alias declarations:

alias foo.bar abc; // is it a type or a symbol?

The distinction is made in the semantic analysis pass.

Aliases cannot be used for expressions:

struct S { static int i; }
S s;

alias s.i a; // illegal, s.i is an expression
alias S.i b; // ok
b = 4;       // sets S.i to 4

Extern Declarations

Variable declarations with the storage class extern are not allocated storage within the module. They must be defined in some other object file with a matching name which is then linked in. The primary usefulness of this is to connect with global variable declarations in C files.

typeof

Typeof:
    typeof ( Expression )
   typeof ( return )

Typeof is a way to specify a type based on the type of an expression. For example:

void func(int i) {
 typeof(i) j;       // j is of type int
 typeof(3 + 6.0) x; // x is of type double
 typeof(1)* p;      // p is of type pointer to int
 int[typeof(p)] a;  // a is of type int[int*]

 writefln("%d", typeof('c').sizeof); // prints 1
 double c = cast(typeof(1.0))j; // cast j to double
}

Expression is not evaluated, just the type of it is generated:

void func() {
 int i = 1;
 typeof(++i) j; // j is declared to be an int, i is not incremented
 writefln("%d", i);  // prints 1
}

There are three special cases:

  1. typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function.
  2. Analogously, typeof(super) will generate the type of what super would be in a non-static member function.
  3. typeof(return) will, when inside a function scope, give the return type of that function.
class A { }

class B : A {
 typeof(this) x;  // x is declared to be a B
 typeof(super) y; // y is declared to be an A
}

struct C {
 static typeof(this) z;  // z is declared to be a C
 typeof(super) q; // error, no super struct for C
}

typeof(this) r;   // error, no enclosing struct or class

Where Typeof is most useful is in writing generic template code.

Void Initializations

VoidInitializer:
    void

Normally, variables are initialized either with an explicit Initializer or are set to the default value for the type of the variable. If the Initializer is void, however, the variable is not initialized. If its value is used before it is set, undefined program behavior will result.

void foo() {
 int x = void;
 writefln(x);  // will print garbage
}

Therefore, one should only use void initializers as a last resort when optimizing critical code.

Global and Static Initializers

The Initializer for a global or static variable must be evaluatable at compile time. Whether some pointers can be initialized with the addresses of other functions or data is implementation defined. Runtime initialization can be done with static constructors.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Types - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Types

Basic Data Types

Basic Data Types
Keyword | Description | Default Initializer (.init)
void | no type | -
bool | boolean value | false
byte | signed 8 bits | 0
ubyte | unsigned 8 bits | 0
short | signed 16 bits | 0
ushort | unsigned 16 bits | 0
int | signed 32 bits | 0
uint | unsigned 32 bits | 0
long | signed 64 bits | 0L
ulong | unsigned 64 bits | 0L
cent | signed 128 bits (reserved for future use) | 0
ucent | unsigned 128 bits (reserved for future use) | 0
float | 32 bit floating point | float.nan
double | 64 bit floating point | double.nan
real | largest hardware implemented floating point size (Implementation Note: 80 bits for x86 CPUs) or double size, whichever is larger | real.nan
ifloat | imaginary float | float.nan * 1.0i
idouble | imaginary double | double.nan * 1.0i
ireal | imaginary real | real.nan * 1.0i
cfloat | a complex number of two float values | float.nan + float.nan * 1.0i
cdouble | complex double | double.nan + double.nan * 1.0i
creal | complex real | real.nan + real.nan * 1.0i
char | unsigned 8 bit UTF-8 | 0xFF
wchar | unsigned 16 bit UTF-16 | 0xFFFF
dchar | unsigned 32 bit UTF-32 | 0x0000FFFF

Derived Data Types

  • pointer
  • array
  • associative array
  • function
  • delegate

Strings are a special case of arrays.

User Defined Types

  • alias
  • enum
  • struct
  • union
  • class

Base Types

The base type of an enum is the type it is based on:

enum E : T { ... }  // T is the base type of E

Pointer Conversions

Casting pointers to non-pointers and vice versa is allowed in D, however, do not do this for any pointers that point to data allocated by the garbage collector.

Implicit Conversions

Implicit conversions are used to automatically convert types as required.

A enum can be implicitly converted to its base type, but going the other way requires an explicit conversion. For example:

int i;
enum Foo { E }
Foo f;
i = f;           // OK
f = i;           // error
f = cast(Foo)i;  // OK
f = 0;           // error
f = Foo.E;       // OK

Integer Promotions

Integer Promotions are conversions of the following types:

Integer Promotions
from | to
bool | int
byte | int
ubyte | int
short | int
ushort | int
char | int
wchar | int
dchar | uint

If a enum has as a base type one of the types in the left column, it is converted to the type in the right column.

Usual Arithmetic Conversions

The usual arithmetic conversions convert operands of binary operators to a common type. The operands must already be of arithmetic types. The following rules are applied in order, looking at the base type:

  1. If either operand is real, the other operand is converted to real.
  2. Else if either operand is double, the other operand is converted to double.
  3. Else if either operand is float, the other operand is converted to float.
  4. Else the integer promotions are done on each operand, followed by:
    1. If both are the same type, no more conversions are done.
    2. If both are signed or both are unsigned, the smaller type is converted to the larger.
    3. If the signed type is larger than the unsigned type, the unsigned type is converted to the signed type.
    4. The signed type is converted to the unsigned type.

If one or both of the operand types is an enum after undergoing the above conversions, the result type is:

  1. If the operands are the same type, the result will be the that type.
  2. If one operand is an enum and the other is the base type of that enum, the result is the base type.
  3. If the two operands are different enums, the result is the closest base type common to both. A base type being closer means there is a shorter sequence of conversions to base type to get there from the original type.

Integer values cannot be implicitly converted to another type that cannot represent the integer bit pattern after integral promotion. For example:

ubyte  u1 = cast(byte)-1;  // error, -1 cannot be represented in a ubyte
ushort u2 = cast(short)-1; // error, -1 cannot be represented in a ushort
uint   u3 = cast(int)-1;   // ok, -1 can be represented in a uint
ulong  u4 = cast(long)-1; // ok, -1 can be represented in a ulong

Floating point types cannot be implicitly converted to integral types.

Complex floating point types cannot be implicitly converted to non-complex floating point types.

Imaginary floating point types cannot be implicitly converted to float, double, or real types. Float, double, or real types cannot be implicitly converted to imaginary floating point types.

bool

The bool type is a 1 byte size type that can only hold the value true or false. The only operators that can accept operands of type bool are: & | ^ &= |= ^= ! && || ?:. A bool value can be implicitly converted to any integral type, with false becoming 0 and true becoming 1. The numeric literals 0 and 1 can be implicitly converted to the bool values false and true, respectively. Casting an expression to bool means testing for 0 or !=0 for arithmetic types, and null or !=null for pointers or references.

Delegates

There are no pointers-to-members in D, but a more useful concept called delegates are supported. Delegates are an aggregate of two pieces of data: an object reference and a pointer to a non-static member function, or a pointer to a closure and a pointer to a nested function. The object reference forms the this pointer when the function is called.

Delegates are declared similarly to function pointers, except that the keyword delegate takes the place of (*), and the identifier occurs afterwards:

int function(int) fp; // fp is pointer to a function
int delegate(int) dg; // dg is a delegate to a function

The C style syntax for declaring pointers to functions is deprecated:

int (*fp)(int);  // fp is pointer to a function

A delegate is initialized analogously to function pointers:

int func(int);
fp = &func;   // fp points to func

class OB {
    int member(int);
}
OB o;
dg = &o.member; // dg is a delegate to object o and
                // member function member

Delegates cannot be initialized with static member functions or non-member functions.

Delegates are called analogously to function pointers:

fp(3);   // call func(3)
dg(3);   // call o.member(3)

The equivalent of member function pointers can be constructed using anonymous lambda functions:

class C {
  int a;
  int foo(int i) { return i + a; }
}

// mfp is the member function pointer
auto mfp = function(C self, int i) { return self.foo(i); };
auto c = new C();  // create an instance of C
mfp(c, 1);  // and call c.foo(1)

size_t And ptrdiff_t

size_t is an alias to one of the unsigned integral basic types, and represents a type that is large enough to represent an offset into all addressible memory.

ptrdiff_t is an alias to the signed basic type the same size as size_t.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Properties - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Properties

Every type and expression has properties that can be queried:

Property Examples
Expression | Value
int.sizeof | yields 4
float.nan | yields the floating point nan (Not A Number) value
(float).nan | yields the floating point nan value
(3).sizeof | yields 4 (because 3 is an int)
int.init | default initializer for int's
int.mangleof | yields the string "i"
int.stringof | yields the string "int"
(1+2).stringof | yields the string "1 + 2"

Properties for All Types
Property | Description
.init | initializer
.sizeof | size in bytes (equivalent to C's sizeof(type))
.alignof | alignment size
.mangleof | string representing the ‘mangled’ representation of the type
.stringof | string representing the source representation of the type

Properties for Integral Types
Property | Description
.init | initializer (0)
.max | maximum value
.min | minimum value

Properties for Floating Point Types
Property | Description
.init | initializer (NaN)
.infinity | infinity value
.nan | NaN value
.dig | number of decimal digits of precision
.epsilon | smallest increment to the value 1
.mant_dig | number of bits in mantissa
.max_10_exp | maximum int value such that 10max_10_exp is representable
.max_exp | maximum int value such that 2max_exp-1 is representable
.min_10_exp | minimum int value such that 10min_10_exp is representable as a normalized value
.min_exp | minimum int value such that 2min_exp-1 is representable as a normalized value
.max | largest representable value that's not infinity
.min_normal | smallest representable normalized value that's not 0
.re | real part
.im | imaginary part

Properties for Class Types
Property | Description
.classinfo | Information about the dynamic type of the class

.init Property

.init produces a constant expression that is the default initializer. If applied to a type, it is the default initializer for that type. If applied to a variable or field, it is the default initializer for that variable or field's type. For example:

int a;
int b = 1;
typedef int t = 2;
t c;
t d = cast(t)3;

int.init // is 0
a.init   // is 0
b.init   // is 0
t.init   // is 2
c.init   // is 2
d.init   // is 2

struct Foo {
  int a;
  int b = 7;
}

Foo.init.a  // is 0
Foo.init.b  // is 7

Note: .init produces a default initialized object, not default constructed. That means using .init is sometimes incorrect.

  1. If T is a nested struct, the context pointer in T.init is null.
    2. void main() {
  int a;
  struct S {
    void foo() { a = 1; }  // access a variable in enclosing scope
  }
  S s1;           // OK. S() correctly initialize its frame pointer.
  S s2 = S();     // OK. same as s1
  S s3 = S.init;  // Bad. the frame pointer in s3 is null
  s3.foo();       // Access violation
}
  2. If T is a struct which has @disable this();, T.init might return a logically incorrect object.
    3. struct S {
  int a;
  @disable this();
  this(int n) { a = n; }
  invariant() { assert(a > 0); }
  void check() {}
}
void main() {
//S s1;           // Error: variable s1 initializer required for type S
//S s2 = S();     // Error: constructor S.this is not callable
                  // because it is annotated with @disable
  S s3 = S.init;  // Bad. s3.a == 0, and it violates the invariant of S.
  s3.check();     // Assertion failure.
}

.stringof Property

.stringof produces a constant string that is the source representation of its prefix. If applied to a type, it is the string for that type. If applied to an expression, it is the source representation of that expression. Semantic analysis is not done for that expression. For example:

module test;
import std.stdio;

struct Foo { }

enum Enum { RED }

typedef int myint;

void main() {
  writeln((1+2).stringof);       // "1 + 2"
  writeln(Foo.stringof);         // "Foo"
  writeln(test.Foo.stringof);    // "Foo"
  writeln(int.stringof);         // "int"
  writeln((int*[5][]).stringof); // "int*[5u][]"
  writeln(Enum.RED.stringof);    // "cast(enum)0"
  writeln(test.myint.stringof);  // "myint"
  writeln((5).stringof);         // "5"
}

.sizeof Property

e.sizeof gives the size in bytes of the expression e.

When getting the size of a member, it is not necessary for there to be a this object:

struct S {
  int a;
  static int foo() {
    return a.sizeof; // returns 4
  }
}

void test() {
  int x = S.a.sizeof; // sets x to 4
}

.sizeof applied to a class object returns the size of the class reference, not the class instantiation.

.alignof Property

.alignof gives the aligned size of an expression or type. For example, an aligned size of 1 means that it is aligned on a byte boundary, 4 means it is aligned on a 32 bit boundary.

.classinfo Property

.classinfo provides information about the dynamic type of a class object. It returns a reference to type object.TypeInfo_Class.

.classinfo applied to an interface gives the information for the interface, not the class it might be an instance of.

User Defined Properties

Properties are functions that can be syntactically treated as if they were fields or variables. Properties can be read from or written to. A property is read by calling a methhod or function with no arguments; a property is written by calling a method or function with its argument being the value it is set to.

A simple property would be:

struct Foo {
  @property int data() { return m_data; } // read property

  @property int data(int value) { return m_data = value; } // write property

private:
  int m_data;
}

Properties are marked with the @property attribute. Properties may only have zero or one parameter, and may not be variadic. Property functions may not be overloaded with non-property functions.

To use it:

int test() {
  Foo f;

  f.data = 3;        // same as f.data(3);
  return f.data + 3; // same as return f.data() + 3;
}

The absence of a read method means that the property is write-only. The absence of a write method means that the property is read-only. Multiple write methods can exist; the correct one is selected using the usual function overloading rules.

In all the other respects, these methods are like any other methods. They can be static, have different linkages, have their address taken, etc.

Note: Properties can be the lvalue of an op=, ++, or -- operator if they return a ref.

The built in properties .sizeof, .alignof, and .mangleof may not be declared as fields or methods in structs, unions, classes or enums.

If a .property is applied to a user-defined property, the .property is applied to the result of the function call.

void main() {
  @property int[] delegate() bar1 = { return [1, 2]; };
  auto x1 = bar1.ptr; // points to array data

  struct Foo { int* ptr; }
  @property Foo delegate() bar2 = { return Foo(); };
  auto x2 = bar2.ptr; // gets value of Foo.ptr
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Attributes - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Attributes

AttributeSpecifier:
    Attribute :
    Attribute DeclarationBlock

Attribute:
    LinkageAttribute
    AlignAttribute
    Pragma
    deprecated
    ProtectionAttribute
    static
    extern
    final
    synchronized
    override
    abstract
    const
    auto
    scope
    __gshared
    shared
    immutable
    inout
    @disable

DeclarationBlock:
    DeclDef
    { DeclDefsopt }

Attributes are a way to modify one or more declarations. The general forms are:

attribute declaration; // affects the declaration

attribute:     // affects all declarations until the end of
               // the current scope
  declaration;
  declaration;
  ...

attribute {    // affects all declarations in the block
  declaration;
  declaration;
  ...
}

Linkage Attribute

LinkageAttribute:
    extern ( LinkageType )

LinkageType:
    C
    C++
    D
    Windows
    Pascal
    System

D provides an easy way to call C functions and operating system API functions, as compatibility with both is essential. The LinkageType is case sensitive, and is meant to be extensible by the implementation (they are not keywords). C and D must be supplied, the others are what makes sense for the implementation. C++ is reserved for future use. System is the same as Windows on Windows platforms, and C on other platforms. Implementation Note: for Win32 platforms, Windows and Pascal should exist.

C function calling conventions are specified by:

extern (C):
  int foo(); // call foo() with C conventions

D conventions are:

extern (D):

or:

extern:

Windows API conventions are:

extern (Windows):
  void *VirtualAlloc(
    void *lpAddress,
    uint dwSize,
    uint flAllocationType,
    uint flProtect
    );

Align Attribute

AlignAttribute:
    align
    align ( IntegerLiteral )

Specifies the alignment of:

  1. variables
  2. struct fields
  3. union fields
  4. class fields
  5. struct, union, and class types

align by itself sets it to the default, which matches the default member alignment of the companion C compiler.

struct S {
  align:
     byte a;   // placed at offset 0
     int b;    // placed at offset 4
     long c;   // placed at offset 8
}

auto sz = S.sizeof;  // 16

IntegerLiteral specifies the alignment which matches the behavior of the companion C compiler when non-default alignments are used. It must be a positive power of 2.

A value of 1 means that no alignment is done; fields are packed together.

struct S {
  align (1):
     byte a;   // placed at offset 0
     int b;    // placed at offset 1
     long c;   // placed at offset 5
}

auto sz = S.sizeof;  // 16

The alignment for the fields of an aggregate does not affect the alignment of the aggregate itself - that is affected by the alignment setting outside of the aggregate.

align (2) struct S {
  align (1):
     byte a;   // placed at offset 0
     int b;    // placed at offset 1
     long c;   // placed at offset 5
}

auto sz = S.sizeof;  // 14

Setting the alignment of a field aligns it to that power of 2, regardless of the size of the field.

struct S {
  align (4):
     byte a;   // placed at offset 0
     byte b;   // placed at offset 4
     short c;  // placed at offset 8
}

auto sz = S.sizeof;  // 12

Do not align references or pointers that were allocated using NewExpression on boundaries that are not a multiple of size_t. The garbage collector assumes that pointers and references to gc allocated objects will be on size_t byte boundaries. If they are not, undefined behavior will result.

The AlignAttribute is reset to the default when entering a function scope or a non-anonymous struct, union, class, and restored when exiting that scope. It is not inherited from a base class.

Deprecated Attribute

It is often necessary to deprecate a feature in a library, yet retain it for backwards compatibility. Such declarations can be marked as deprecated, which means that the compiler can be set to produce an error if any code refers to deprecated declarations:

deprecated
{
  void oldFoo();
}

Implementation Note: The compiler should have a switch specifying if deprecated declarations should be compiled with out complaint or not.

Protection Attribute

ProtectionAttribute:
    private
    package
    protected
    public
    export

Protection is an attribute that is one of private, package, protected, public or export.

Private means that only members of the enclosing class can access the member, or members and functions in the same module as the enclosing class. Private members cannot be overridden. Private module members are equivalent to static declarations in C programs.

Package extends private so that package members can be accessed from code in other modules that are in the same package. This applies to the innermost package only, if a module is in nested packages.

Protected means that only members of the enclosing class or any classes derived from that class, or members and functions in the same module as the enclosing class, can access the member. If accessing a protected instance member through a derived class member function, that member can only be accessed for the object instance which can be implicitly cast to the same type as ‘this’. Protected module members are illegal.

Public means that any code within the executable can access the member.

Export means that any code outside the executable can access the member. Export is analogous to exporting definitions from a DLL.

Protection does not participate in name lookup. In particular, if two symbols with the same name are in scope, and that name is used unqualified then the lookup will be ambiguous, even if one of the symbols is inaccessible due to protection. For example:

module A;
private class Foo {}

module B;
public class Foo {}

import A;
import B;

Foo f1; // error, could be either A.Foo or B.Foo
B.Foo f2; // ok

Const Attribute

The const attribute declares constants that can be evaluated at compile time. For example:

const int foo = 7;

const {
  double bar = foo + 6;
}

immutable Attribute

__gshared Attribute

By default, non-immutable global declarations reside in thread local storage. When a global variable is marked with the __gshared attribute, its value is shared across all threads.

int foo;            // Each thread has its own exclusive copy of foo.
__gshared int bar;  // bar is shared by all threads.

__gshared may also be applied to member variables and local variables. In these cases, __gshared is equivalent to static, except that the variable is shared by all threads rather than being thread local.

class Foo {
  __gshared int bar;
}

int foo() {
  __gshared int bar = 0;
  return bar++; // Not thread safe.
}

Unlike the shared attribute, __gshared provides no safe-guards against data races or other multi-threaded synchronization issues. It is the responsibility of the programmer to ensure that access to variables marked __gshared is synchronized correctly.

__gshared is disallowed in safe mode.

shared Attribute

inout Attribute

@disable Attribute

A reference to a declaration marked with the @disable attribute causes a compile time error. This can be used to explicitly disallow certain operations or overloads at compile time rather than relying on generating a runtime error.

struct T {
  @disable this(this) { } // disabling this makes T not copyable
}

struct S {
  T t;   // uncopyable member makes S also not copyable
}

@disable void foo() { }

void main() {
  S s;
  S t = s; // error, S is not copyable
  foo();   // error, foo is disabled
}

Override Attribute

The override attribute applies to virtual functions. It means that the function must override a function with the same name and parameters in a base class. The override attribute is useful for catching errors when a base class's member function gets its parameters changed, and all derived classes need to have their overriding functions updated.

class Foo {
  int bar();
  int abc(int x);
}

class Foo2 : Foo {
  override {
    int bar(char c); // error, no bar(char) in Foo
    int abc(int x);  // ok
  }
}

Static Attribute

The static attribute applies to functions and data. It means that the declaration does not apply to a particular instance of an object, but to the type of the object. In other words, it means there is no this reference. static is ignored when applied to other declarations.

class Foo {
  static int bar() { return 6; }
  int foobar() { return 7; }
}

...

Foo f = new Foo;
Foo.bar();      // produces 6
Foo.foobar();   // error, no instance of Foo
f.bar();        // produces 6;
f.foobar();     // produces 7;

Static functions are never virtual.

Static data has only one instance for the entire program, not once per object.

Static does not have the additional C meaning of being local to a file. Use the private attribute in D to achieve that. For example:

module foo;
int x = 3;         // x is global
private int y = 4; // y is local to module foo

Auto Attribute

The auto attribute is used when there are no other attributes and type inference is desired.

auto i = 6.8;   // declare i as a double

Scope Attribute

The scope attribute is used for local variables and for class declarations. For class declarations, the scope attribute creates a scope class. For local declarations, scope implements the RAII (Resource Acquisition Is Initialization) protocol. This means that the destructor for an object is automatically called when the reference to it goes out of scope. The destructor is called even if the scope is exited via a thrown exception, thus scope is used to guarantee cleanup.

If there is more than one scope variable going out of scope at the same point, then the destructors are called in the reverse order that the variables were constructed.

scope cannot be applied to globals, statics, data members, ref or out parameters. Arrays of scopes are not allowed, and scope function return values are not allowed. Assignment to a scope, other than initialization, is not allowed. Rationale: These restrictions may get relaxed in the future if a compelling reason to appears.

Abstract Attribute

If a class is abstract, it cannot be instantiated directly. It can only be instantiated as a base class of another, non-abstract, class.

Classes become abstract if they are defined within an abstract attribute, or if any of the virtual member functions within it are declared as abstract.

Non-virtual functions cannot be declared as abstract.

Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide ‘base class functionality.’

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Pragmas - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Pragmas

Pragma:
    pragma ( Identifier )
    pragma ( Identifier , ArgumentList )

Pragmas are a way to pass special information to the compiler and to add vendor specific extensions to D. Pragmas can be used by themselves terminated with a ‘;’, they can influence a statement, a block of statements, a declaration, or a block of declarations.

Pragmas can appear as either declarations, Pragma DeclarationBlock, or as statements, PragmaStatement.

pragma(ident);        // just by itself

pragma(ident) declaration; // influence one declaration

pragma(ident): // influence subsequent declarations
    declaration;
    declaration;

pragma(ident) { // influence block of declarations
    declaration;
    declaration;
}

pragma(ident) statement; // influence one statement

pragma(ident) { // influence block of statements
    statement;
    statement;
}

The kind of pragma it is is determined by the Identifier. ExpressionList is a comma-separated list of AssignExpressions. The AssignExpressions must be parsable as expressions, but what they mean semantically is up to the individual pragma semantics.

Predefined Pragmas

All implementations must support these, even if by just ignoring them:

msg
Constructs a message from the arguments and prints to the standard error stream while compiling:
pragma(msg, "compiling...", 1, 1.0);
lib
Inserts a directive in the object file to link in the library specified by the AssignExpression. The AssignExpressions must be a string literal:
pragma(lib, "foo.lib");
startaddress
Puts a directive into the object file saying that the function specified in the first argument will be the start address for the program:
void foo() { ... }
pragma(startaddress, foo);
This is not normally used for application level programming, but is for specialized systems work. For applications code, the start address is taken care of by the runtime library.

Vendor Specific Pragmas

Vendor specific pragma Identifiers can be defined if they are prefixed by the vendor's trademarked name, in a similar manner to version identifiers:

pragma(DigitalMars_funky_extension) { ... }

Compilers must diagnose an error for unrecognized Pragmas, even if they are vendor specific ones. This implies that vendor specific pragmas should be wrapped in version statements:

version (DigitalMars)
{
    pragma(DigitalMars_funky_extension)
    { ... }
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Expressions - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Expressions

C and C++ programmers will find the D expressions very familiar, with a few interesting additions.

Expressions are used to compute values with a resulting type. These values can then be assigned, tested, or ignored. Expressions can also have side effects.

Order Of Evaluation

The following binary expressions are evaluated in strictly left-to-right order:

OrExpression, XorExpression, AndExpression, CmpExpression, ShiftExpression, AddExpression, CatExpression, MulExpression, PowExpression, CommaExpression, OrOrExpression, AndAndExpression

The following binary expressions are evaluated in an implementation-defined order:

AssignExpression, function parameters

It is an error to depend on order of evaluation when it is not specified. For example, the following are illegal:

i = i++;
c = a + (a = b);

If the compiler can determine that the result of an expression is illegally dependent on the order of evaluation, it can issue an error (but is not required to). The ability to detect these kinds of errors is a quality of implementation issue.

The evaluation order of function arguments is defined to be left to right. This is similar to Java but different to C/C++ where the evaluation order is unspecified. Thus, the following code is valid and well defined.

import std.conv;
int i = 0;
assert(text(++i, ++i) == "12"); // left to right evaluation of arguments

But even though the order of evaluation is well defined writing code that depends on it is rarely recommended. Note that dmd currently does not comply with left to right evaluation of function arguments.

Expressions

Expression:
    CommaExpression

CommaExpression:
    AssignExpression
    AssignExpression , CommaExpression
The left operand of the , is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand.

Assign Expressions

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
The right operand is implicitly converted to the type of the left operand, and assigned to it. The result type is the type of the lvalue, and the result value is the value of the lvalue after the assignment.

The left operand must be an lvalue.

Assignment Operator Expressions

Assignment operator expressions, such as:
a op= b
are semantically equivalent to:
a = cast(typeof(a))(a op b)

except that:

  • operand a is only evaluated once
  • overloading op uses a different function than overloading op= does
  • the left operand of >>>= does not undergo integral promotions before shifting

Conditional Expressions

ConditionalExpression:
    OrOrExpression
    OrOrExpression ? Expression : ConditionalExpression
The first expression is converted to bool, and is evaluated. If it is true, then the second expression is evaluated, and its result is the result of the conditional expression. If it is false, then the third expression is evaluated, and its result is the result of the conditional expression. If either the second or third expressions are of type void, then the resulting type is void. Otherwise, the second and third expressions are implicitly converted to a common type which becomes the result type of the conditional expression.

OrOr Expressions

OrOrExpression:
    AndAndExpression
    OrOrExpression || AndAndExpression
The result type of an OrOrExpression is bool, unless the right operand has type void, when the result is type void.

The OrOrExpression evaluates its left operand. If the left operand, converted to type bool, evaluates to true, then the right operand is not evaluated. If the result type of the OrOrExpression is bool then the result of the expression is true. If the left operand is false, then the right operand is evaluated. If the result type of the OrOrExpression is bool then the result of the expression is the right operand converted to type bool.

AndAnd Expressions

AndAndExpression:
    OrExpression
    AndAndExpression && OrExpression
    CmpExpression
    AndAndExpression && CmpExpression

The result type of an AndAndExpression is bool, unless the right operand has type void, when the result is type void.

The AndAndExpression evaluates its left operand.

If the left operand, converted to type bool, evaluates to false, then the right operand is not evaluated. If the result type of the AndAndExpression is bool then the result of the expression is false.

If the left operand is true, then the right operand is evaluated. If the result type of the AndAndExpression is bool then the result of the expression is the right operand converted to type bool.

Bitwise Expressions

Bit wise expressions perform a bitwise operation on their operands. Their operands must be integral types. First, the default integral promotions are done. Then, the bitwise operation is done.

Or Expressions

OrExpression:
    XorExpression
    OrExpression | XorExpression
The operands are OR'd together.

Xor Expressions

XorExpression:
    AndExpression
    XorExpression ^ AndExpression
The operands are XOR'd together.

And Expressions

AndExpression:
    ShiftExpression
    AndExpression & ShiftExpression
The operands are AND'd together.

Compare Expressions

CmpExpression:
    ShiftExpression
    EqualExpression
    IdentityExpression
    RelExpression
    InExpression

Equality Expressions

EqualExpression:
    ShiftExpression == ShiftExpression
    ShiftExpression != ShiftExpression
Equality expressions compare the two operands for equality (==) or inequality (!=). The type of the result is bool. The operands go through the usual conversions to bring them to a common type before comparison.

If they are integral values or pointers, equality is defined as the bit pattern of the type matches exactly. Equality for struct objects means the bit patterns of the objects match exactly (the existence of alignment holes in the objects is accounted for, usually by setting them all to 0 upon initialization). Equality for floating point types is more complicated. -0 and +0 compare as equal. If either or both operands are NAN, then both the == returns false and != returns true. Otherwise, the bit patterns are compared for equality.

For complex numbers, equality is defined as equivalent to:

x.re == y.re && x.im == y.im
and inequality is defined as equivalent to:
x.re != y.re || x.im != y.im

For class and struct objects, the expression (a == b) is rewritten as a.opEquals(b), and (a != b) is rewritten as !a.opEquals(b).

For class objects, the == and != operators compare the contents of the objects. Therefore, comparing against null is invalid, as null has no contents. Use the is and !is operators instead.

class C;
C c;
if (c == null)  // error
  ...
if (c is null)  // ok
  ...

For static and dynamic arrays, equality is defined as the lengths of the arrays matching, and all the elements are equal.

Identity Expressions

IdentityExpression:
    ShiftExpression is ShiftExpression
    ShiftExpression !is ShiftExpression

The is compares for identity. To compare for not identity, use e1 !is e2. The type of the result is bool. The operands go through the usual conversions to bring them to a common type before comparison.

For class objects, identity is defined as the object references are for the same object. Null class objects can be compared with is.

For struct objects, identity is defined as the bits in the struct being identical.

For static and dynamic arrays, identity is defined as referring to the same array elements and the same number of elements.

For other operand types, identity is defined as being the same as equality.

The identity operator is cannot be overloaded.

Relational Expressions

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
First, the integral promotions are done on the operands. The result type of a relational expression is bool.

For class objects, the result of Object.opCmp() forms the left operand, and 0 forms the right operand. The result of the relational expression (o1 op o2) is:

(o1.opCmp(o2) op 0)
It is an error to compare objects if one is null.

For static and dynamic arrays, the result of the relational op is the result of the operator applied to the first non-equal element of the array. If two arrays compare equal, but are of different lengths, the shorter array compares as "less" than the longer array.

Integer comparisons

Integer comparisons happen when both operands are integral types.

Integer comparison operators
Operator | Relation
< | less
> | greater
<= | less or equal
>= | greater or equal
== | equal
!= | not equal

It is an error to have one operand be signed and the other unsigned for a <, <=, > or >= expression. Use casts to make both operands signed or both operands unsigned.

Floating point comparisons

If one or both operands are floating point, then a floating point comparison is performed.

Useful floating point operations must take into account NAN values. In particular, a relational operator can have NAN operands. The result of a relational operation on float values is less, greater, equal, or unordered (unordered means either or both of the operands is a NAN). That means there are 14 possible comparison conditions to test for:

Floating point comparison operators
Operator | Greater Than | Less Than | Equal | Unordered | Exception | Relation
== | F | F | T | F | no | equal
!= | T | T | F | T | no | unordered, less, or greater
> | T | F | F | F | yes | greater
>= | T | F | T | F | yes | greater or equal
< | F | T | F | F | yes | less
<= | F | T | T | F | yes | less or equal
!<>= | F | F | F | T | no | unordered
<> | T | T | F | F | yes | less or greater
<>= | T | T | T | F | yes | less, equal, or greater
!<= | T | F | F | T | no | unordered or greater
!< | T | F | T | T | no | unordered, greater, or equal
!>= | F | T | F | T | no | unordered or less
!> | F | T | T | T | no | unordered, less, or equal
!<> | F | F | T | T | no | unordered or equal

Notes:

  1. For floating point comparison operators, (a !op b) is not the same as !(a op b).
  2. "Unordered" means one or both of the operands is a NAN.
  3. "Exception" means the Invalid Exception is raised if one of the operands is a NAN. It does not mean an exception is thrown. The Invalid Exception can be checked using the functions in std.c.fenv.

Class comparisons

For class objects, the relational operators compare the contents of the objects. Therefore, comparing against null is invalid, as null has no contents.

class C;
C c;
if (c < null)  // error
  ...

In Expressions

InExpression:
    ShiftExpression in ShiftExpression
  ShiftExpression !in ShiftExpression

An associative array can be tested to see if an element is in the array:

int foo[char[]];
...
if ("hello" in foo)
    ...

The in expression has the same precedence as the relational expressions <, <=, etc. The return value of the InExpression is null if the element is not in the array; if it is in the array it is a pointer to the element.

The !in expression is the logical negation of the in operation.

Shift Expressions

ShiftExpression:
    AddExpression
    ShiftExpression << AddExpression
    ShiftExpression >> AddExpression
    ShiftExpression >>> AddExpression

The operands must be integral types, and undergo the usual integral promotions. The result type is the type of the left operand after the promotions. The result value is the result of shifting the bits by the right operand's value.

<< is a left shift. >> is a signed right shift. >>> is an unsigned right shift.

It's illegal to shift by the same or more bits than the size of the quantity being shifted:

int c;
c << 33;        // error

Add Expressions

AddExpression:
    MulExpression
    AddExpression + MulExpression
    AddExpression - MulExpression
    CatExpression

If the operands are of integral types, they undergo integral promotions, and then are brought to a common type using the usual arithmetic conversions.

If either operand is a floating point type, the other is implicitly converted to floating point and they are brought to a common type via the usual arithmetic conversions.

If the operator is + or -, and the first operand is a pointer, and the second is an integral type, the resulting type is the type of the first operand, and the resulting value is the pointer plus (or minus) the second operand multiplied by the size of the type pointed to by the first operand.

If the second operand is a pointer, and the first is an integral type, and the operator is +, the operands are reversed and the pointer arithmetic just described is applied.

If both operands are pointers, and the operator is +, then it is illegal. For -, the pointers are subtracted and the result is divided by the size of the type pointed to by the operands. It is an error if the pointers point to different types.

If both operands are of integral types and an overflow or underflow occurs in the computation, wrapping will happen. That is, uint.max + 1 == uint.min and uint.min - 1 == uint.max.

Add expressions for floating point operands are not associative.

Cat Expressions

CatExpression:
    AddExpression ~ MulExpression

A CatExpression concatenates arrays, producing a dynmaic array with the result. The arrays must be arrays of the same element type. If one operand is an array and the other is of that array's element type, that element is converted to an array of length 1 of that element, and then the concatenation is performed.

Mul Expressions

MulExpression:
    UnaryExpression
    MulExpression * UnaryExpression
    MulExpression / UnaryExpression
    MulExpression % UnaryExpression

The operands must be arithmetic types. They undergo integral promotions, and then are brought to a common type using the usual arithmetic conversions.

For integral operands, the *, /, and % correspond to multiply, divide, and modulus operations. For multiply, overflows are ignored and simply chopped to fit into the integral type.

For integral operands of the / and % operators, the quotient rounds towards zero and the remainder has the same sign as the dividend. If the divisor is zero, an Exception is thrown.

For floating point operands, the * and / operations correspond to the IEEE 754 floating point equivalents. % is not the same as the IEEE 754 remainder. For example, 15.0 % 10.0 == 5.0, whereas for IEEE 754, remainder(15.0,10.0) == -5.0.

Mul expressions for floating point operands are not associative.

Unary Expressions

UnaryExpression:
    & UnaryExpression
    ++ UnaryExpression
    -- UnaryExpression
    * UnaryExpression
    - UnaryExpression
    + UnaryExpression
    ! UnaryExpression
    ComplementExpression
    ( Type ) . Identifier
    NewExpression
    DeleteExpression
    CastExpression
    PowExpression

Complement Expressions

ComplementExpression:
    ~ UnaryExpression

ComplementExpressions work on integral types (except bool). All the bits in the value are complemented.

Note: unlike in C and C++, the usual integral promotions are not performed prior to the complement operation.

New Expressions

NewExpression:
    new AllocatorArgumentsopt Type [ AssignExpression ]
    new AllocatorArgumentsopt Type ( ArgumentList )
    new AllocatorArgumentsopt Type
    NewAnonClassExpression

AllocatorArguments:
    ( ArgumentListopt )

ArgumentList:
    AssignExpression
    AssignExpression ,
    AssignExpression , ArgumentList

NewExpressions are used to allocate memory on the garbage collected heap (default) or using a class or struct specific allocator.

To allocate multidimensional arrays, the declaration reads in the same order as the prefix array declaration order.

char[][] foo;   // dynamic array of strings
...
foo = new char[][30]; // allocate array of 30 strings

The above allocation can also be written as:

foo = new char[][](30); // allocate array of 30 strings

To allocate the nested arrays, multiple arguments can be used:

int[][][] bar;
...
bar = new int[][][](5,20,30);

Which is equivalent to:

bar = new int[][][5];
foreach (ref a; bar)
{
  a = new int[][20];
  foreach (ref b; a)
  {
    b = new int[30];
  }
}

If there is a new ( ArgumentList ), then those arguments are passed to the class or struct specific allocator function after the size argument.

If a NewExpression is used as an initializer for a function local variable with scope storage class, and the ArgumentList to new is empty, then the instance is allocated on the stack rather than the heap or using the class specific allocator.

Delete Expressions

DeleteExpression:
    delete UnaryExpression

If the UnaryExpression is a class object reference, and there is a destructor for that class, the destructor is called for that object instance.

Next, if the UnaryExpression is a class object reference, or a pointer to a struct instance, and the class or struct has overloaded operator delete, then that operator delete is called for that class object instance or struct instance.

Otherwise, the garbage collector is called to immediately free the memory allocated for the class instance or struct instance. If the garbage collector was not used to allocate the memory for the instance, undefined behavior will result.

If the UnaryExpression is a pointer or a dynamic array, the garbage collector is called to immediately release the memory. If the garbage collector was not used to allocate the memory for the instance, undefined behavior will result.

The pointer, dynamic array, or reference is set to null after the delete is performed. Any attempt to reference the data after the deletion via another reference to it will result in undefined behavior.

If UnaryExpression is a variable allocated on the stack, the class destructor (if any) is called for that instance. Neither the garbage collector nor any class deallocator is called.

Cast Expressions

CastExpression:
    cast ( Type ) UnaryExpression
    cast ( CastQual ) UnaryExpression
    cast ( ) UnaryExpression

CastQual:
    const
    const shared
    shared const
    inout
    inout shared
    shared inout
    immutable
    shared

A CastExpression converts the UnaryExpression to Type.

cast(foo) -p; // cast (-p) to type foo
(foo) - p;      // subtract p from foo

Any casting of a class reference to a derived class reference is done with a runtime check to make sure it really is a downcast. null is the result if it isn't. Note: This is equivalent to the behavior of the dynamic_cast operator in C++.

class A { ... }
class B : A { ... }

void test(A a, B b) {
  B bx = a;         // error, need cast
  B bx = cast(B) a; // bx is null if a is not a B
  A ax = b;         // no cast needed
  A ax = cast(A) b; // no runtime check needed for upcast
}

In order to determine if an object o is an instance of a class B use a cast:

if (cast(B) o)
{
  // o is an instance of B
}
else
{
  // o is not an instance of B
}

Casting a pointer type to and from a class type is done as a type paint (i.e. a reinterpret cast).

Casting a dynamic array to another dynamic array is done only if the array lengths multiplied by the element sizes match. The cast is done as a type paint, with the array length adjusted to match any change in element size. If there's not a match, a runtime error is generated.

import std.stdio;

int main() {
  byte[] a = [1,2,3];
  auto b = cast(int[])a; // runtime array cast misalignment

  int[] c = [1, 2, 3];
  auto d = cast(byte[])c; // ok
  // prints:
  // [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]
  writeln(d);
  return 0;
}

Casting a floating point literal from one type to another changes its type, but internally it is retained at full precision for the purposes of constant folding.

void test() {
  real a = 3.40483L;
  real b;
  b = 3.40483;     // literal is not truncated to double precision
  assert(a == b);
  assert(a == 3.40483);
  assert(a == 3.40483L);
  assert(a == 3.40483F);
  double d = 3.40483; // truncate literal when assigned to variable
  assert(d != a);     // so it is no longer the same
  const double x = 3.40483; // assignment to const is not
  assert(x == a);     // truncated if the initializer is visible
}

Casting a value v to a struct S, when value is not a struct of the same type, is equivalent to:

S(v)

Casting to a CastQual replaces the qualifiers to the type of the UnaryExpression.

shared int x;
assert(is(typeof(cast(const)x) == const int));

Casting with no Type or CastQual removes any top level const, immutable, shared or inout type modifiers from the type of the UnaryExpression.

shared int x;
assert(is(typeof(cast()x) == int));

Pow Expressions

PowExpression:
    PostfixExpression
    PostfixExpression ^^ UnaryExpression

PowExpression raises its left operand to the power of its right operand.

Postfix Expressions

PostfixExpression:
    PrimaryExpression
    PostfixExpression . Identifier
    PostfixExpression . TemplateInstance
    PostfixExpression . NewExpression
    PostfixExpression ++
    PostfixExpression --
    PostfixExpression ( )
    PostfixExpression ( ArgumentList )
    TypeCtorsopt BasicType ( )
    TypeCtorsopt BasicType ( ArgumentList )
    IndexExpression
    SliceExpression

Index Expressions

IndexExpression:
    PostfixExpression [ ArgumentList ]

PostfixExpression is evaluated. If PostfixExpression is an expression of type static array or dynamic array, the symbol $ is set to be the the number of elements in the array. If PostfixExpression is an ExpressionTuple, the symbol $ is set to be the the number of elements in the tuple. A new declaration scope is created for the evaluation of the ArgumentList and $ appears in that scope only.

If PostfixExpression is an ExpressionTuple, then the ArgumentList must consist of only one argument, and that must be statically evaluatable to an integral constant. That integral constant n then selects the nth expression in the ExpressionTuple, which is the result of the IndexExpression. It is an error if n is out of bounds of the ExpressionTuple.

Slice Expressions

SliceExpression:
    PostfixExpression [ ]
    PostfixExpression [ AssignExpression .. AssignExpression ]

PostfixExpression is evaluated. if PostfixExpression is an expression of type static array or dynamic array, the variable length (and the special variable $) is declared and set to be the length of the array. A new declaration scope is created for the evaluation of the AssignExpression..AssignExpression and length (and $) appears in that scope only.

The first AssignExpression is taken to be the inclusive lower bound of the slice, and the second AssignExpression is the exclusive upper bound. The result of the expression is a slice of the PostfixExpression array.

If the [ ] form is used, the slice is of the entire array.

The type of the slice is a dynamic array of the element type of the PostfixExpression.

A SliceExpression is not a modifiable lvalue.

If PostfixExpression is an ExpressionTuple, then the result of the slice is a new ExpressionTuple formed from the upper and lower bounds, which must statically evaluate to integral constants. It is an error if those bounds are out of range.

Primary Expressions

PrimaryExpression:
    Identifier
    .Identifier
    TemplateInstance
    .TemplateInstance
    this
    super
    null
    true
    false
    $
    __FILE__
    __LINE__
    IntegerLiteral
    FloatLiteral
    CharacterLiteral
    StringLiterals
    ArrayLiteral
    AssocArrayLiteral
    Lambda
    FunctionLiteral
    AssertExpression
    MixinExpression
    ImportExpression
    BasicType . Identifier
    Typeof
    TypeidExpression
    IsExpression
    ( Expression )
    TraitsExpression

.Identifier

Identifier is looked up at module scope, rather than the current lexically nested scope.

this

Within a non-static member function, this resolves to a reference to the object for which the function was called. If the object is an instance of a struct, this will be a pointer to that instance. If a member function is called with an explicit reference to typeof(this), a non-virtual call is made:

class A {
  char get() { return 'A'; }

  char foo() { return typeof(this).get(); }
  char bar() { return this.get(); }
}

class B : A {
  char get() { return 'B'; }
}

void main() {
  B b = new B();

  b.foo();  // returns 'A'
  b.bar();  // returns 'B'
}

Assignment to this is not allowed.

super

super is identical to this, except that it is cast to this's base class. It is an error if there is no base class. It is an error to use super within a struct member function. (Only class Object has no base class.) If a member function is called with an explicit reference to super, a non-virtual call is made.

Assignment to super is not allowed.

null

null represents the null value for pointers, pointers to functions, delegates, dynamic arrays, associative arrays, and class objects. If it has not already been cast to a type, it is given the type (void *) and it is an exact conversion to convert it to the null value for pointers, pointers to functions, delegates, etc. After it is cast to a type, such conversions are implicit, but no longer exact.

true, false

These are of type bool and when cast to another integral type become the values 1 and 0, respectively.

Character Literals

Character literals are single characters and resolve to one of type char, wchar, or dchar. If the literal is a \u escape sequence, it resolves to type wchar. If the literal is a \U escape sequence, it resolves to type dchar. Otherwise, it resolves to the type with the smallest size it will fit into.

String Literals

StringLiterals:
    StringLiteral
    StringLiterals StringLiteral

String literals can implicitly convert to any of the following types, they have equal weight:

immutable(char)*
immutable(wchar)*
immutable(dchar)*
immutable(char)[]
immutable(wchar)[]
immutable(dchar)[]

String literals have a 0 appended to them, which makes them easy to pass to C or C++ functions expecting a const char* string. The 0 is not included in the .length property of the string literal.

Array Literals

ArrayLiteral:
    [ ArgumentList ]

Array literals are a comma-separated list of AssignExpressions between square brackets [ and ]. The AssignExpressions form the elements of a static array, the length of the array is the number of elements. The type of the first element is taken to be the type of all the elements, and all elements are implicitly converted to that type. If that type is a static array, it is converted to a dynamic array.

[1,2,3];  // type is int[3], with elements 1, 2 and 3
[1u,2,3]; // type is uint[3], with elements 1u, 2u, and 3u

If any of the arguments in the ArgumentList are an ExpressionTuple, then the elements of the ExpressionTuple are inserted as arguments in place of the tuple.

Array literals are allocated on the memory managed heap. Thus, they can be returned safely from functions:

int[] foo() {
  return [1, 2, 3];
}

When array literals are cast to another array type, each element of the array is cast to the new element type. When arrays that are not literals are cast, the array is reinterpreted as the new type, and the length is recomputed:

import std.stdio;

void main() {
  // cast array literal
  const short[] ct = cast(short[]) [cast(byte)1, 1];
  writeln(ct);  // writes [1, 1]

  // cast other array expression
  short[] rt = cast(short[]) [cast(byte)1, cast(byte)1].dup;
  writeln(rt);  // writes [257]
}

Associative Array Literals

AssocArrayLiteral:
    [ KeyValuePairs ]

KeyValuePairs:
    KeyValuePair
    KeyValuePair , KeyValuePairs

KeyValuePair:
    KeyExpression : ValueExpression

KeyExpression:
    AssignExpression

ValueExpression:
    AssignExpression

Associative array literals are a comma-separated list of key:value pairs between square brackets [ and ]. The list cannot be empty. The type of the first key is taken to be the type of all the keys, and all subsequent keys are implicitly converted to that type. The type of the first value is taken to be the type of all the values, and all subsequent values are implicitly converted to that type. An AssocArrayLiteral cannot be used to statically initialize anything.

[21u:"he",38:"ho",2:"hi"]; // type is char[2][uint],
                           // with keys 21u, 38u and 2u
                           // and values "he", "ho", and "hi"

If any of the keys or values in the KeyValuePairs are an ExpressionTuple, then the elements of the ExpressionTuple are inserted as arguments in place of the tuple.

Lambdas

Lambda:
        Identifier => AssignExpression
        ParameterAttributes => AssignExpression

Lambdas are a shorthand syntax for FunctionLiterals. The first form is equivalent to:

delegate ( Identifier ) { return AssignExpression; }

And the second:

delegate ParameterAttributes { return AssignExpression; }
Example usage:
import std.stdio;

void main() {
    auto i=3;
    auto square = (int x) => x*x;
    auto twice  = (int x) => x*2;

    writeln(square(i));  // prints 9
    writeln(twice(i));   // prints 6
}

Function Literals

FunctionLiteral:
        function Typeopt ParameterAttributes opt FunctionBody
        delegate Typeopt ParameterAttributes opt FunctionBody
        ParameterAttributes FunctionBody
        FunctionBody

ParameterAttributes:
    Parameters
    Parameters FunctionAttributes
FunctionLiterals enable embedding anonymous functions and anonymous delegates directly into expressions. Type is the return type of the function or delegate, if omitted it is inferred from any ReturnStatements in the FunctionBody. ( ArgumentList ) forms the arguments to the function. If omitted it defaults to the empty argument list ( ). The type of a function literal is pointer to function or pointer to delegate. If the keywords function or delegate are omitted, it defaults to being a delegate.

For example:

int function(char c) fp; // declare pointer to a function

void test() {
  static int foo(char c) { return 6; }

  fp = &foo;
}
is exactly equivalent to:
int function(char c) fp;

void test() {
  fp = function int(char c) { return 6;} ;
}
And:
int abc(int delegate(long i));

void test() {
  int b = 3;
  int foo(long c) { return 6 + b; }

  abc(&foo);
}
is exactly equivalent to:
int abc(int delegate(long i));

void test() {
  int b = 3;

  abc( delegate int(long c) { return 6 + b; } );
}

and the following where the return type int is inferred:

int abc(int delegate(long i));

void test() {
  int b = 3;

  abc( (long c) { return 6 + b; } );
}
Anonymous delegates can behave like arbitrary statement literals. For example, here an arbitrary statement is executed by a loop:
double test() {
  double d = 7.6;
  float f = 2.3;

  void loop(int k, int j, void delegate() statement) {
    for (int i = k; i < j; i++) {
      statement();
    }
  }

  loop(5, 100, { d += 1; } );
  loop(3, 10,  { f += 3; } );

  return d + f;
}
When comparing with nested functions, the function form is analogous to static or non-nested functions, and the delegate form is analogous to non-static nested functions. In other words, a delegate literal can access stack variables in its enclosing function, a function literal cannot.

Assert Expressions

AssertExpression:
    assert ( AssignExpression )
    assert ( AssignExpression , AssignExpression )

Asserts evaluate the AssignExpression. If it evaluates to a non-null class reference, the class invariant is run. Otherwise, if it evaluates to a non-null pointer to a struct, the struct invariant is run. Otherwise, if the result is false, an AssertError is thrown. If the result is true, then no exception is thrown. It is an error if the expression contains any side effects that the program depends on. The compiler may optionally not evaluate assert expressions at all. The result type of an assert expression is void. Asserts are a fundamental part of the Contract Programming support in D.

The expression assert(0) is a special case; it signifies that it is unreachable code. Either AssertError is thrown at runtime if it is reachable, or the execution is halted (on the x86 processor, a HLT instruction can be used to halt execution). The optimization and code generation phases of compilation may assume that it is unreachable code.

The second AssignExpression, if present, must be implicitly convertible to type const(char)[]. It is evaluated if the result is false, and the string result is appended to the AssertError's message.

void main() {
  assert(0, "an" ~ " error message");
}

When compiled and run, it will produce the message:

Error: AssertError Failure test.d(3) an error message

Mixin Expressions

MixinExpression:
    mixin ( AssignExpression )

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid AssignExpression, and is compiled as such.

int foo(int x) {
  return mixin("x + 1") * 7;  // same as ((x + 1) * 7)
}

Import Expressions

ImportExpression:
    import ( AssignExpression )

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string are interpreted as a file name. The file is read, and the exact contents of the file become a string literal.

Implementations may restrict the file name in order to avoid directory traversal security vulnerabilities. A possible restriction might be to disallow any path components in the file name.

void foo() {
  // Prints contents of file foo.txt
  writeln( import("foo.txt") );
}

Typeid Expressions

TypeidExpression:
    typeid ( Type )
    typeid ( Expression )

If Type, returns an instance of class TypeInfo corresponding to Type.

If Expression, returns an instance of class TypeInfo corresponding to the type of the Expression. If the type is a class, it returns the TypeInfo of the dynamic type (i.e. the most derived type). The Expression is always executed.

class A { }
class B : A { }

void main() {
  writeln(typeid(int));  // int
  uint i;
  writeln(typeid(i++));  // uint
  writeln(i);            // 1
  A a = new B();
  writeln(typeid(a));    // B
  writeln(typeid(typeof(a)));  // A
}

IsExpression

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
    __parameters
IsExpressions are evaluated at compile time and are used for checking for valid types, comparing types for equivalence, determining if one type can be implicitly converted to another, and deducing the subtypes of a type. The result of an IsExpression is an int of type 0 if the condition is not satisified, 1 if it is.

Type is the type being tested. It must be syntactically correct, but it need not be semantically correct. If it is not semantically correct, the condition is not satisfied.

Identifier is declared to be an alias of the resulting type if the condition is satisfied. The Identifier forms can only be used if the IsExpression appears in a StaticIfCondition.

TypeSpecialization is the type that Type is being compared against.

The forms of the IsExpression are:

  1. is ( Type )
    The condition is satisfied if Type is semantically correct (it must be syntactically correct regardless).
    alias int func(int);    // func is a alias to a function type
void foo() {
  if (is(func[]) ) // not satisfied because arrays of
                        // functions are not allowed
    writeln("satisfied");
  else
    writeln("not satisfied");

  if (is([][]))  // error, [][] is not a syntactically valid type
    ...
}
  2. is ( Type : TypeSpecialization )
    The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. TypeSpecialization is only allowed to be a Type.
    alias short bar;
void foo(bar x) {
  if ( is(bar : int) )   // satisfied because short can be
                              // implicitly converted to int
    writeln("satisfied");
  else
    writeln("not satisfied");
}
  3. is ( Type == TypeSpecialization )
    The condition is satisfied if Type is semantically correct and is the same type as TypeSpecialization.

    If TypeSpecialization is one of struct union class interface enum function delegate const immutable shared then the condition is satisifed if Type is one of those.

    alias short bar;

void test(bar x) {
  if ( is(bar == int) ) // not satisfied because short is not
                        // the same type as int
    writeln("satisfied");
  else
    writeln("not satisfied");
}
  4. is ( Type Identifier )
    The condition is satisfied if Type is semantically correct. If so, Identifier is declared to be an alias of Type.
    alias short bar;
void foo(bar x) {
  static if ( is(bar T) )
    alias T S;
  else
    alias long S;

  writeln(typeid(S));  // prints "short"
  if ( is(bar T) )  // error, Identifier T form can
                      // only be in StaticIfConditions
    ...
}
  5. is ( Type Identifier : TypeSpecialization )

    The condition is satisfied if Type is the same as TypeSpecialization, or if Type is a class and TypeSpecialization is a base class or base interface of it. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type.

    alias int bar;
alias long* abc;
void foo(bar x, abc a) {
  static if ( is(bar T : int) )
    alias T S;
  else
    alias long S;

  writeln(typeid(S));  // prints "int"

  static if ( is(abc U : U*) )
  {
    U u;
    writeln(typeid(typeof(u)));  // prints "long"
  }
}

    The way the type of Identifier is determined is analogous to the way template parameter types are determined by TemplateTypeParameterSpecialization.

  6. is ( Type Identifier == TypeSpecialization )

    The condition is satisfied if Type is semantically correct and is the same as TypeSpecialization. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type.

    If TypeSpecialization is one of struct union class interface enum function delegate const immutable shared then the condition is satisifed if Type is one of those. Furthermore, Identifier is set to be an alias of the type:

    keyword | alias type for Identifier
    struct | Type
    union | Type
    class | Type
    interface | Type
    super | TypeTuple of base classes and interfaces
    enum | the base type of the enum
    function | TypeTuple of the function parameter types. For C- and D-style variadic functions, only the non-variadic parameters are included. For typesafe variadic functions, the ... is ignored.
    delegate | the function type of the delegate
    return | the return type of the function, delegate, or function pointer
    __parameters | the parameter tuple of a function, delegate, or function pointer. This includes the parameter types, names, and default values.
    const | Type
    immutable | Type
    shared | Type
    alias short bar;
enum E : byte { Emember }
void foo(bar x) {
  static if ( is(bar T == int) ) // not satisfied, short is not int
    alias T S;
  alias T U;       // error, T is not defined

  static if ( is(E V == enum) )  // satisified, E is an enum
    V v;           // v is declared to be a byte
}
  7. is ( Type Identifier : TypeSpecialization , TemplateParameterList )
    is ( Type Identifier == TypeSpecialization , TemplateParameterList )

    More complex types can be pattern matched; the TemplateParameterList declares symbols based on the parts of the pattern that are matched, analogously to the way implied template parameters are matched.

    import std.stdio;

void main() {
  alias long[char[]] AA;

  static if (is(AA T : T[U], U : const char[]))
  {
    writeln(typeid(T));  // long
    writeln(typeid(U));  // const char[]
  }

  static if (is(AA A : A[B], B : int))
  {
    assert(0);  // should not match, as B is not an int
  }

  static if (is(int[10] W : W[V], int V))
  {
    writeln(typeid(W));  // int
    writeln(V);          // 10
  }

  static if (is(int[10] X : X[Y], int Y : 5))
  {
    assert(0);  // should not match, Y should be 10
  }
}

Associativity and Commutativity

An implementation may rearrange the evaluation of expressions according to arithmetic associativity and commutativity rules as long as, within that thread of execution, no observable difference is possible.

This rule precludes any associative or commutative reordering of floating point expressions.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Statements - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Statements

C and C++ programmers will find the D statements very familiar, with a few interesting additions.
Statement:
    ;
    NonEmptyStatement
    ScopeBlockStatement

NoScopeNonEmptyStatement:
    NonEmptyStatement
    BlockStatement

NoScopeStatement:
    ;
    NonEmptyStatement
    BlockStatement

NonEmptyOrScopeBlockStatement:
    NonEmptyStatement
    ScopeBlockStatement

NonEmptyStatement:
    NonEmptyStatementNoCaseNoDefault
    CaseStatement
    CaseRangeStatement
    DefaultStatement

NonEmptyStatementNoCaseNoDefault:
    LabeledStatement
    ExpressionStatement
    DeclarationStatement
    IfStatement
    WhileStatement
    DoStatement
    ForStatement
    ForeachStatement
    SwitchStatement
    FinalSwitchStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    GotoStatement
    WithStatement
    SynchronizedStatement
    TryStatement
    ScopeGuardStatement
    ThrowStatement
    AsmStatement
    PragmaStatement
    MixinStatement
    ForeachRangeStatement
    ConditionalStatement
    StaticAssert
    TemplateMixin
    ImportDeclaration

Any ambiguities in the grammar between Statements and Declarations are resolved by the declarations taking precedence. If a Statement is desired instead, wrapping it in parentheses will disambiguate it in favor of being a Statement.

Scope Statements

ScopeStatement:
    NonEmptyStatement
    BlockStatement

A new scope for local symbols is introduced for the NonEmptyStatement or BlockStatement.

Even though a new scope is introduced, local symbol declarations cannot shadow (hide) other local symbol declarations in the same function.

void func1(int x) {
  int x;    // illegal, x shadows parameter x

  int y;

  { int y; } // illegal, y shadows enclosing scope's y

  void delegate() dg;
  dg = { int y; }; // ok, this y is not in the same function

  struct S {
    int y;    // ok, this y is a member, not a local
  }

  { int z; }
  { int z; }  // ok, this z is not shadowing the other z

  { int t; }
  { t++;   }  // illegal, t is undefined
}

The idea is to avoid bugs in complex functions caused by scoped declarations inadvertently hiding previous ones. Local names should all be unique within a function.

Scope Block Statements

ScopeBlockStatement:
    BlockStatement

A scope block statement introduces a new scope for the BlockStatement.

Labeled Statements

Statements can be labeled. A label is an identifier that precedes a statement.

LabeledStatement:
    Identifier : NoScopeStatement

Any statement can be labeled, including empty statements, and so can serve as the target of a goto statement. Labeled statements can also serve as the target of a break or continue statement.

Labels are in a name space independent of declarations, variables, types, etc. Even so, labels cannot have the same name as local declarations. The label name space is the body of the function they appear in. Label name spaces do not nest, i.e. a label inside a block statement is accessible from outside that block.

Block Statement

BlockStatement:
    { }
    { StatementList }

StatementList:
    Statement
    Statement StatementList

A block statement is a sequence of statements enclosed by { }. The statements are executed in lexical order.

Expression Statement

ExpressionStatement:
    Expression ;
The expression is evaluated.

Expressions that have no effect, like (x + x), are illegal in expression statements. If such an expression is needed, casting it to void will make it legal.

int x;
x++;               // ok
x;                 // illegal
1+1;               // illegal
cast(void)(x + x); // ok

Declaration Statement

Declaration statements declare variables and types.
DeclarationStatement:
    Declaration

Some declaration statements:

int a;        // declare a as type int and initialize it to 0
struct S { }  // declare struct s
alias int myint;

If Statement

If statements provide simple conditional execution of statements.
IfStatement:
    if ( IfCondition ) ThenStatement
    if ( IfCondition ) ThenStatement else ElseStatement

IfCondition:
    Expression
    auto Identifier = Expression
    BasicType Declarator = Expression

ThenStatement:
    ScopeStatement

ElseStatement:
    ScopeStatement
Expression is evaluated and must have a type that can be converted to a boolean. If it's true the ThenStatement is transferred to, else the ElseStatement is transferred to.

The 'dangling else' parsing problem is solved by associating the else with the nearest if statement.

If an auto Identifier is provided, it is declared and initialized to the value and type of the Expression. Its scope extends from when it is initialized to the end of the ThenStatement.

If a Declarator is provided, it is declared and initialized to the value of the Expression. Its scope extends from when it is initialized to the end of the ThenStatement.

import std.regexp;
...
if (auto m = std.regexp.search("abcdef", "b(c)d"))
{
  writefln("[%s]", m.pre);      // prints [a]
  writefln("[%s]", m.post);     // prints [ef]
  writefln("[%s]", m.match(0)); // prints [bcd]
  writefln("[%s]", m.match(1)); // prints [c]
  writefln("[%s]", m.match(2)); // prints []
}
else
{
  writefln(m.post);    // error, m undefined
}
writefln(m.pre);         // error, m undefined

While Statement

WhileStatement:
    while ( Expression ) ScopeStatement
While statements implement simple loops. Expression is evaluated and must have a type that can be converted to a boolean. If it's true the ScopeStatement is executed. After the ScopeStatement is executed, the Expression is evaluated again, and if true the ScopeStatement is executed again. This continues until the Expression evaluates to false.
int i = 0;
while (i < 10) {
  foo(i);
  i++;
}
A BreakStatement will exit the loop. A ContinueStatement will transfer directly to evaluating Expression again.

Do Statement

DoStatement:
    do ScopeStatement while ( Expression ) ;
Do while statements implement simple loops. ScopeStatement is executed. Then Expression is evaluated and must have a type that can be converted to a boolean. If it's true the loop is iterated again. This continues until the Expression evaluates to false.
int i = 0;
do {
  foo(i);
} while (++i < 10);
A BreakStatement will exit the loop. A ContinueStatement will transfer directly to evaluating Expression again.

For Statement

For statements implement loops with initialization, test, and increment clauses.
ForStatement:
    for (Initialize Testopt ; Incrementopt) ScopeStatement

Initialize:
    ;
    NoScopeNonEmptyStatement

Test:
    Expression

Increment:
    Expression

Initialize is executed. Test is evaluated and must have a type that can be converted to a boolean. If it's true the statement is executed. After the statement is executed, the Increment is executed. Then Test is evaluated again, and if true the statement is executed again. This continues until the Test evaluates to false.

A BreakStatement will exit the loop. A ContinueStatement will transfer directly to the Increment.

A ForStatement creates a new scope. If Initialize declares a variable, that variable's scope extends through the end of the for statement. For example:

for (int i = 0; i < 10; i++)
  foo(i);
is equivalent to:
{
  int i;
  for (i = 0; i < 10; i++)
    foo(i);
}
Function bodies cannot be empty:
for (int i = 0; i < 10; i++)
  ;       // illegal
Use instead:
for (int i = 0; i < 10; i++)
{
}
The Initialize may be omitted. Test may also be omitted, and if so, it is treated as if it evaluated to true.

Foreach Statement

A foreach statement loops over the contents of an aggregate.
ForeachStatement:
    Foreach (ForeachTypeList ; Aggregate) NoScopeNonEmptyStatement

Foreach:
    foreach
    foreach_reverse

ForeachTypeList:
    ForeachType
    ForeachType , ForeachTypeList

ForeachType:
    refopt BasicType Declarator
    refopt Identifier

Aggregate:
    Expression

Aggregate is evaluated. It must evaluate to an expression of type static array, dynamic array, associative array, struct, class, delegate, or tuple. The NoScopeNonEmptyStatement is executed, once for each element of the aggregate. At the start of each iteration, the variables declared by the ForeachTypeList are set to be a copy of the elements of the aggregate. If the variable is ref, it is a reference to the contents of that aggregate.

The aggregate must be loop invariant, meaning that elements to the aggregate cannot be added or removed from it in the NoScopeNonEmptyStatement.

Foreach over Arrays

If the aggregate is a static or dynamic array, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the array, one by one. The type of the variable must match the type of the array contents, except for the special cases outlined below. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of int, uint or size_t type, it cannot be ref, and it is set to be the index of the array element.

char[] a;
...
foreach (int i, char c; a)
{
  writefln("a[%d] = '%c'", i, c);
}

For foreach, the elements for the array are iterated over starting at index 0 and continuing to the maximum of the array. For foreach_reverse, the array elements are visited in the reverse order.

Foreach over Arrays of Characters

If the aggregate expression is a static or dynamic array of chars, wchars, or dchars, then the Type of the value can be any of char, wchar, or dchar. In this manner any UTF array can be decoded into any UTF type:

char[] a = "\xE2\x89\xA0".dup;  // \u2260 encoded as 3 UTF-8 bytes

foreach (dchar c; a)
{
  writefln("a[] = %x", c); // prints 'a[] = 2260'
}

dchar[] b = "\u2260"d.dup;

foreach (char c; b)
{
  writef("%x, ", c);  // prints 'e2, 89, a0, '
}

Aggregates can be string literals, which can be accessed as char, wchar, or dchar arrays:

void test() {
  foreach (char c; "ab") {
    writefln("'%s'", c);
  }
  foreach (wchar w; "xy") {
    writefln("'%s'", w);
  }
}

which would print:

'a'
'b'
'x'
'y'

Foreach over Associative Arrays

If the aggregate expression is an associative array, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the array, one by one. The type of the variable must match the type of the array contents. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of the same type as the indexing type of the associative array. It cannot be ref, and it is set to be the index of the array element. The order in which the elements of the array is unspecified for foreach. foreach_reverse for associative arrays is illegal.

double[string] a; // index type is string, value type is double
...
foreach (string s, double d; a)
{
  writefln("a['%s'] = %g", s, d);
}

Foreach over Structs and Classes with Ranges

Iteration over struct and class objects can be done with ranges, which means the following properties and methods must be defined:

Foreach Range Properties
Property | Purpose
.empty | returns true if no more elements
.front | return the leftmost element of the range
.back | return the rightmost element of the range
Foreach Range Methods
Method | Purpose
.popFront() | move the left edge of the range right one
.popBack() | move the right edge of the range left one

Meaning:

foreach (e; range) { ... }

translates to:

for (auto __r = range; !__r.empty; __r.popFront())
{
  auto e = __r.front;
  ...
}

Similarly:

foreach_reverse (e; range) { ... }

translates to:

for (auto __r = range; !__r.empty; __r.popBack())
{
  auto e = __r.back;
  ...
}

If the foreach range properties do not exist, the opApply method will be used instead.

Foreach over Structs and Classes with opApply

If it is a struct or class object, the foreach is defined by the special opApply member function. The foreach_reverse behavior is defined by the special opApplyReverse member function. These special functions must be defined by the type in order to use the corresponding foreach statement. The functions have the type:

int opApply(int delegate(ref Type [, ...]) dg);

int opApplyReverse(int delegate(ref Type [, ...]) dg);

where Type matches the Type used in the ForeachType declaration of Identifier. Multiple ForeachTypes correspond with multiple Type's in the delegate type passed to opApply or opApplyReverse. There can be multiple opApply and opApplyReverse functions, one is selected by matching the type of dg to the ForeachTypes of the ForeachStatement. The body of the apply function iterates over the elements it aggregates, passing them each to the dg function. If the dg returns 0, then apply goes on to the next element. If the dg returns a nonzero value, apply must cease iterating and return that value. Otherwise, after done iterating across all the elements, apply will return 0.

For example, consider a class that is a container for two elements:

class Foo {
  uint[2] array;

  int opApply(int delegate(ref uint) dg)
  {
    int result = 0;

    for (int i = 0; i < array.length; i++)
    {
      result = dg(array[i]);
      if (result)
        break;
    }
    return result;
  }
}
An example using this might be:
void test() {
  Foo a = new Foo();

  a.array[0] = 73;
  a.array[1] = 82;

  foreach (uint u; a)
  {
    writefln("%d", u);
  }
}
which would print:
73
82

Foreach over Delegates

If Aggregate is a delegate, the type signature of the delegate is of the same as for opApply. This enables many different named looping strategies to coexist in the same class or struct.

Foreach over Tuples

If the aggregate expression is a tuple, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the tuple, one by one. If the type of the variable is given, it must match the type of the tuple contents. If it is not given, the type of the variable is set to the type of the tuple element, which may change from iteration to iteration. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of int or uint type, it cannot be ref, and it is set to be the index of the tuple element.

If the tuple is a list of types, then the foreach statement is executed once for each type, and the value is aliased to that type.

import std.stdio;
import std.typetuple; // for TypeTuple

void main() {
  alias TypeTuple!(int, long, double) TL;

  foreach (T; TL)
  {
    writeln(typeid(T));
  }
}

Prints:

int
long
double

Foreach Ref Parameters

ref can be used to update the original elements:

void test() {
  static uint[2] a = [7, 8];

  foreach (ref uint u; a)
  {
    u++;
  }
  foreach (uint u; a)
  {
    writefln("%d", u);
  }
}
which would print:
8
9

ref can not be applied to the index values.

If not specified, the Types in the ForeachType can be inferred from the type of the Aggregate.

Foreach Restrictions

The aggregate itself must not be resized, reallocated, free'd, reassigned or destructed while the foreach is iterating over the elements.

int[] a;
int[] b;
foreach (int i; a)
{
  a = null;       // error
  a.length += 10; // error
  a = b;          // error
}
a = null;         // ok

Foreach Range Statement

A foreach range statement loops over the specified range.
ForeachRangeStatement:
    Foreach (ForeachType ; LwrExpression .. UprExpression ) ScopeStatement

LwrExpression:
    Expression

UprExpression:
    Expression

ForeachType declares a variable with either an explicit type, or a type inferred from LwrExpression and UprExpression. The ScopeStatement is then executed n times, where n is the result of UprExpression - LwrExpression. If UprExpression is less than or equal to LwrExpression, the ScopeStatement is executed zero times. If Foreach is foreach, then the variable is set to LwrExpression, then incremented at the end of each iteration. If Foreach is foreach_reverse, then the variable is set to UprExpression, then decremented before each iteration. LwrExpression and UprExpression are each evaluated exactly once, regardless of how many times the ScopeStatement is executed.

import std.stdio;

int foo() {
  write("foo");
  return 10;
}

void main() {
  foreach (i; 0 .. foo())
  {
    write(i);
  }
}

Prints:

foo0123456789

Break and Continue out of Foreach

A BreakStatement in the body of the foreach will exit the foreach, a ContinueStatement will immediately start the next iteration.

Switch Statement

A switch statement goes to one of a collection of case statements depending on the value of the switch expression.
SwitchStatement:
    switch ( Expression ) ScopeStatement

CaseStatement:
    case ArgumentList : ScopeStatementList

CaseRangeStatement:
    case FirstExp : .. case LastExp : ScopeStatementList

FirstExp:
    AssignExpression

LastExp:
    AssignExpression

DefaultStatement:
    default : ScopeStatementList

ScopeStatementList:
    StatementListNoCaseNoDefault

StatementListNoCaseNoDefault:
    StatementNoCaseNoDefault
    StatementNoCaseNoDefault StatementListNoCaseNoDefault

StatementNoCaseNoDefault:
    ;
    NonEmptyStatementNoCaseNoDefault
    ScopeBlockStatement

Expression is evaluated. The result type T must be of integral type or char[], wchar[] or dchar[]. The result is compared against each of the case expressions. If there is a match, the corresponding case statement is transferred to.

The case expressions, ArgumentList, are a comma separated list of expressions.

A CaseRangeStatement is a shorthand for listing a series of case statements from FirstExp to LastExp.

If none of the case expressions match, and there is a default statement, the default statement is transferred to.

A switch statement must have a default statement.

The case expressions must all evaluate to a constant value or array, or a runtime initialized const or immutable variable of integral type. They must be implicitly convertible to the type of the switch Expression.

Case expressions must all evaluate to distinct values. Const or immutable variables must all have different names. If they share a value, the first case statement with that value gets control. There must be exactly one default statement.

The ScopeStatementList introduces a new scope.

Case statements and default statements associated with the switch can be nested within block statements; they do not have to be in the outermost block. For example, this is allowed:

switch (i) {
  case 1:
  {
    case 2:
  }
    break;
}

A ScopeStatementList must either be empty, or be ended with a ContinueStatement, BreakStatement, ReturnStatement, GotoStatement, ThrowStatement or assert(0) expression unless this is the last case. This is to set apart with C's error-prone implicit fall-through behavior. goto case; could be used for explicit fall-through:

int number;
string message;
switch (number)
{
  default:    // valid: ends with 'throw'
    throw new Exception("unknown number");

  case 3:     // valid: ends with 'break' (break out of the 'switch' only)
    message ~= "three ";
    break;

  case 4:     // valid: ends with 'continue' (continue the enclosing loop)
    message ~= "four ";
    continue;

  case 5:     // valid: ends with 'goto' (explicit fall-through to next case.)
    message ~= "five ";
    goto case;

  case 6:     // ERROR: implicit fall-through
    message ~= "six ";

  case 1:     // valid: the body is empty
  case 2:     // valid: this is the last case in the switch statement.
    message = "one or two";
}

A break statement will exit the switch BlockStatement.

Strings can be used in switch expressions. For example:

char[] name;
...
switch (name) {
  case "fred":
  case "sally":
    ...
}

For applications like command line switch processing, this can lead to much more straightforward code, being clearer and less error prone. char, wchar and dchar strings are allowed.

Implementation Note: The compiler's code generator may assume that the case statements are sorted by frequency of use, with the most frequent appearing first and the least frequent last. Although this is irrelevant as far as program correctness is concerned, it is of performance interest.

Final Switch Statement

FinalSwitchStatement:
    final switch ( Expression ) ScopeStatement

A final switch statement is just like a switch statement, except that:

  • No DefaultStatement is allowed.
  • No CaseRangeStatements are allowed.
  • If the switch Expression is of enum type, all the enum members must appear in the CaseStatements.
  • The case expressions cannot evaluate to a run time initialized value.

Continue Statement

ContinueStatement:
    continue Identifieropt ;
A continue aborts the current iteration of its enclosing loop statement, and starts the next iteration. continue executes the next iteration of its innermost enclosing while, for, foreach, or do loop. The increment clause is executed.

If continue is followed by Identifier, the Identifier must be the label of an enclosing while, for, or do loop, and the next iteration of that loop is executed. It is an error if there is no such statement.

Any intervening finally clauses are executed, and any intervening synchronization objects are released.

Note: If a finally clause executes a return, throw, or goto out of the finally clause, the continue target is never reached.

for (i = 0; i < 10; i++)
{
  if (foo(i))
    continue;
  bar();
}

Break Statement

BreakStatement:
    break Identifieropt ;
A break exits the enclosing statement. break exits the innermost enclosing while, for, foreach, do, or switch statement, resuming execution at the statement following it.

If break is followed by Identifier, the Identifier must be the label of an enclosing while, for, do or switch statement, and that statement is exited. It is an error if there is no such statement.

Any intervening finally clauses are executed, and any intervening synchronization objects are released.

Note: If a finally clause executes a return, throw, or goto out of the finally clause, the break target is never reached.

for (i = 0; i < 10; i++)
{
  if (foo(i))
    break;
}

Return Statement

ReturnStatement:
    return Expressionopt ;
A return exits the current function and supplies its return value. Expression is required if the function specifies a return type that is not void. The Expression is implicitly converted to the function return type.

At least one return statement, throw statement, or assert(0) expression is required if the function specifies a return type that is not void, unless the function contains inline assembler code.

Before the function actually returns, any objects with scope storage duration are destroyed, any enclosing finally clauses are executed, any scope(exit) statements are executed, any scope(success) statements are executed, and any enclosing synchronization objects are released.

The function will not return if any enclosing finally clause does a return, goto or throw that exits the finally clause.

If there is an out postcondition (see Contract Programming), that postcondition is executed after the Expression is evaluated and before the function actually returns.

int foo(int x)
{
    return x + 3;
}

Goto Statement

GotoStatement:
    goto Identifier ;
    goto default ;
    goto case ;
    goto case Expression ;
A goto transfers to the statement labeled with Identifier.
  if (foo)
    goto L1;
  x = 3;
L1:
  x++;
The second form, goto default;, transfers to the innermost DefaultStatement of an enclosing SwitchStatement.

The third form, goto case;, transfers to the next CaseStatement of the innermost enclosing SwitchStatement.

The fourth form, goto case Expression;, transfers to the CaseStatement of the innermost enclosing SwitchStatement with a matching Expression.

switch (x)
{
  case 3:
    goto case;
  case 4:
    goto default;
  case 5:
    goto case 4;
  default:
    x = 4;
    break;
}
Any intervening finally clauses are executed, along with releasing any intervening synchronization mutexes.

It is illegal for a GotoStatement to be used to skip initializations.

With Statement

The with statement is a way to simplify repeated references to the same object.
WithStatement:
    with ( Expression ) ScopeStatement
    with ( Symbol ) ScopeStatement
    with ( TemplateInstance ) ScopeStatement
where Expression evaluates to a class reference or struct instance. Within the with body the referenced object is searched first for identifier symbols. The WithStatement
with (expression)
{
  ...
  ident;
}
is semantically equivalent to:
{
  Object tmp;
  tmp = expression;
  ...
  tmp.ident;
}

Note that Expression only gets evaluated once. The with statement does not change what this or super refer to.

For Symbol which is a scope or TemplateInstance, the corresponding scope is searched when looking up symbols. For example:

struct Foo {
  alias int Y;
}
...
Y y;        // error, Y undefined
with (Foo) {
  Y y;      // same as Foo.Y y;
}

Use of with object symbols that shadow local symbols with the same identifier are not allowed. This is to reduce the risk of inadvertant breakage of with statements when new members are added to the object declaration.

struct S {
  float x;
}

void main() {
  int x;
  S s;
  with (s) {
    x++;  // error, shadows the int x declaration
  }
}

Synchronized Statement

The synchronized statement wraps a statement with a mutex to synchronize access among multiple threads.

SynchronizedStatement:
    synchronized ScopeStatement
    synchronized ( Expression ) ScopeStatement

Synchronized allows only one thread at a time to execute ScopeStatement by using a mutex.

What mutex is used is determined by the Expression. If there is no Expression, then a global mutex is created, one per such synchronized statement. Different synchronized statements will have different global mutexes.

If there is an Expression, it must evaluate to either an Object or an instance of an Interface, in which case it is cast to the Object instance that implemented that Interface. The mutex used is specific to that Object instance, and is shared by all synchronized statements referring to that instance.

The synchronization gets released even if ScopeStatement terminates with an exception, goto, or return.

Example:

synchronized { ... }

This implements a standard critical section.

Synchronized statements support recursive locking; that is, a function wrapped in synchronized is allowed to recursively call itself and the behavior will be as expected: The mutex will be locked and unlocked as many times as there is recursion.

Try Statement

Exception handling is done with the try-catch-finally statement.
TryStatement:
    try ScopeStatement Catches
    try ScopeStatement Catches FinallyStatement
    try ScopeStatement FinallyStatement

Catches:
    LastCatch
    Catch
    Catch Catches

LastCatch:
    catch NoScopeNonEmptyStatement

Catch:
    catch ( CatchParameter ) NoScopeNonEmptyStatement

CatchParameter:
    BasicType Identifier

FinallyStatement:
    finally NoScopeNonEmptyStatement

CatchParameter declares a variable v of type T, where T is Throwable or derived from Throwable. v is initialized by the throw expression if T is of the same type or a base class of the throw expression. The catch clause will be executed if the exception object is of type T or derived from T.

If just type T is given and no variable v, then the catch clause is still executed.

It is an error if any CatchParameter type T1 hides a subsequent Catch with type T2, i.e. it is an error if T1 is the same type as or a base class of T2.

LastCatch catches all exceptions.

The FinallyStatement is always executed, whether the try ScopeStatement exits with a goto, break, continue, return, exception, or fall-through.

If an exception is raised in the FinallyStatement and is not caught before the original exception is caught, it is chained to the previous exception via the next member of Throwable. Note that, in contrast to most other programming languages, the new exception does not replace the original exception. Instead, later exceptions are regarded as 'collateral damage' caused by the first exception. The original exception must be caught, and this results in the capture of the entire chain.

Thrown objects derived from Error are treated differently. They bypass the normal chaining mechanism, such that the chain can only be caught by catching the first Error. In addition to the list of subsequent exceptions, Error also contains a pointer that points to the original exception (the head of the chain) if a bypass occurred, so that the entire exception history is retained.

import std.stdio;

int main() {
  try {
    try {
      throw new Exception("first");
    }
    finally {
      writefln("finally");
      throw new Exception("second");
    }
  }
  catch(Exception e) {
    writefln("catch %s", e.msg);
  }
  writefln("done");
  return 0;
}
prints:
finally
catch first
done

A FinallyStatement may not exit with a goto, break, continue, or return; nor may it be entered with a goto.

A FinallyStatement may not contain any Catches. This restriction may be relaxed in future versions.

Throw Statement

Throw an exception.
ThrowStatement:
    throw Expression ;
Expression is evaluated and must be a Throwable reference. The Throwable reference is thrown as an exception.
throw new Exception("message");

Scope Guard Statement

ScopeGuardStatement:
    scope(exit) NonEmptyOrScopeBlockStatement
    scope(success) NonEmptyOrScopeBlockStatement
    scope(failure) NonEmptyOrScopeBlockStatement
The ScopeGuardStatement executes NonEmptyOrScopeBlockStatement at the close of the current scope, rather than at the point where the ScopeGuardStatement appears. scope(exit) executes NonEmptyOrScopeBlockStatement when the scope exits normally or when it exits due to exception unwinding. scope(failure) executes NonEmptyOrScopeBlockStatement when the scope exits due to exception unwinding. scope(success) executes NonEmptyOrScopeBlockStatement when the scope exits normally.

If there are multiple ScopeGuardStatements in a scope, they are executed in the reverse lexical order in which they appear. If any scope instances are to be destructed upon the close of the scope, they also are interleaved with the ScopeGuardStatements in the reverse lexical order in which they appear.

write("1"); {
  write("2");
  scope(exit) write("3");
  scope(exit) write("4");
  write("5");
}
writeln();
writes:
12543

{
  scope(exit) write("1");
  scope(success) write("2");
  scope(exit) write("3");
  scope(success) write("4");
}
writeln();
writes:
4321

class Foo {
  this() { write("0"); }
  ~this() { write("1"); }
}

try {
  scope(exit) write("2");
  scope(success) write("3");
  scope Foo f = new Foo();
  scope(failure) write("4");
  throw new Exception("msg");
  scope(exit) write("5");
  scope(success) write("6");
  scope(failure) write("7");
}
catch (Exception e) {
}
writeln();
writes:
0412
A scope(exit) or scope(success) statement may not exit with a throw, goto, break, continue, or return; nor may it be entered with a goto.

Asm Statement

Inline assembler is supported with the asm statement:
AsmStatement:
    asm { }
    asm { AsmInstructionList }

AsmInstructionList:
    AsmInstruction ;
    AsmInstruction ; AsmInstructionList
An asm statement enables the direct use of assembly language instructions. This makes it easy to obtain direct access to special CPU features without resorting to an external assembler. The D compiler will take care of the function calling conventions, stack setup, etc.

The format of the instructions is, of course, highly dependent on the native instruction set of the target CPU, and so is implementation defined. But, the format will follow the following conventions:

  • It must use the same tokens as the D language uses.
  • The comment form must match the D language comments.
  • Asm instructions are terminated by a ;, not by an end of line.
These rules exist to ensure that D source code can be tokenized independently of syntactic or semantic analysis.

For example, for the Intel Pentium:

int x = 3;
asm {
  mov EAX,x; // load x and put it in register EAX
}
Inline assembler can be used to access hardware directly:
int gethardware() {
  asm {
    mov EAX, dword ptr 0x1234;
  }
}
For some D implementations, such as a translator from D to C, an inline assembler makes no sense, and need not be implemented. The version statement can be used to account for this:
version (D_InlineAsm_X86)
{
  asm {
    ...
  }
}
else
{
  /* ... some workaround ... */
}

Semantically consecutive AsmStatements shall not have any other instructions (such as register save or restores) inserted between them by the compiler.

Pragma Statement

PragmaStatement:
    Pragma NoScopeStatement

Mixin Statement

MixinStatement:
    mixin ( AssignExpression ) ;

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid StatementList, and is compiled as such.

import std.stdio;

void main() {
  int j;
  mixin("
    int x = 3;
    for (int i = 0; i < 3; i++)
      writefln(x + i, ++j);
    ");    // ok

  const char[] s = "int y;";
  mixin(s);  // ok
  y = 4;     // ok, mixin declared y

  char[] t = "y = 3;";
  mixin(t);  // error, t is not evaluatable at compile time

  mixin("y =") 4; // error, string must be complete statement

  mixin("y =" ~ "4;");  // ok
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Arrays - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Arrays

There are four kinds of arrays:

Kinds of Arrays
Syntax | Description
type* | Pointers to data
type[integer] | Static arrays
type[] | Dynamic arrays
type[type] | Associative arrays

Pointers

int* p;

These are simple pointers to data, analogous to C pointers. Pointers are provided for interfacing with C and for specialized systems work. There is no length associated with it, and so there is no way for the compiler or runtime to do bounds checking, etc., on it. Most conventional uses for pointers can be replaced with dynamic arrays, out and ref parameters, and reference types.

Static Arrays

int[3] s;

These are analogous to C arrays. Static arrays are distinguished by having a length fixed at compile time.

The total size of a static array cannot exceed 16Mb. A dynamic array should be used instead for such large arrays.

A static array with a dimension of 0 is allowed, but no space is allocated for it. It's useful as the last member of a variable length struct, or as the degenerate case of a template expansion.

Static arrays are value types. Unlike in C and D version 1, static arrays are passed to functions by value. Static arrays can also be returned by functions.

Dynamic Arrays

int[] a;

Dynamic arrays consist of a length and a pointer to the array data. Multiple dynamic arrays can share all or parts of the array data.

Array Declarations

There are two ways to declare arrays, prefix and postfix. The prefix form is the preferred method, especially for non-trivial types.

Prefix Array Declarations

Prefix declarations appear before the identifier being declared and read right to left, so:

int[] a;      // dynamic array of ints
int[4][3] b;  // array of 3 arrays of 4 ints each
int[][5] c;   // array of 5 dynamic arrays of ints.
int*[]*[3] d; // array of 3 pointers to dynamic arrays of pointers to ints
int[]* e;     // pointer to dynamic array of ints

Postfix Array Declarations

Postfix declarations appear after the identifier being declared and read left to right. Each group lists equivalent declarations:

// dynamic array of ints
int[] a;
int a[];

// array of 3 arrays of 4 ints each
int[4][3] b;
int[4] b[3];
int b[3][4];

// array of 5 dynamic arrays of ints.
int[][5] c;
int[] c[5];
int c[5][];

// array of 3 pointers to dynamic arrays of pointers to ints
int*[]*[3] d;
int*[]* d[3];
int* (*d[3])[];

// pointer to dynamic array of ints
int[]* e;
int (*e)[];

Rationale: The postfix form matches the way arrays are declared in C and C++, and supporting this form provides an easy migration path for programmers used to it.

Usage

There are two broad kinds of operations to do on an array - affecting the handle to the array, and affecting the contents of the array. C only has operators to affect the handle. In D, both are accessible.

The handle to an array is specified by naming the array, as in p, s or a:

int* p;
int[3] s;
int[] a;

int* q;
int[3] t;
int[] b;

p = q;     // p points to the same thing q does.
p = s.ptr; // p points to the first element of the array s.
p = a.ptr; // p points to the first element of the array a.

s = ...;   // error, since s is a compiled in static
           // reference to an array.

a = p;     // error, since the length of the array pointed
           // to by p is unknown
a = s;     // a is initialized to point to the s array
a = b;     // a points to the same array as b does

Slicing

Slicing an array means to specify a subarray of it. An array slice does not copy the data, it is only another reference to it. For example:

int[10] a;   // declare array of 10 ints
int[] b;

b = a[1..3]; // a[1..3] is a 2 element array consisting of
             // a[1] and a[2]
foo(b[1]);   // equivalent to foo(0)
a[2] = 3;
foo(b[1]);   // equivalent to foo(3)

The [] is shorthand for a slice of the entire array. For example, the assignments to b:

int[10] a;
int[] b;

b = a;
b = a[];
b = a[0 .. a.length];

are all semantically equivalent.

Slicing is not only handy for referring to parts of other arrays, but for converting pointers into bounds-checked arrays:

int* p;
int[] b = p[0..8];

Array Copying

When the slice operator appears as the lvalue of an assignment expression, it means that the contents of the array are the target of the assignment rather than a reference to the array. Array copying happens when the lvalue is a slice, and the rvalue is an array of or pointer to the same type.

int[3] s;
int[3] t;

s[] = t;           // the 3 elements of t[3] are copied into s[3]
s[] = t[];         // the 3 elements of t[3] are copied into s[3]
s[1..2] = t[0..1]; // same as s[1] = t[0]
s[0..2] = t[1..3]; // same as s[0] = t[1], s[1] = t[2]
s[0..4] = t[0..4]; // error, only 3 elements in s
s[0..2] = t;       // error, different lengths for lvalue and rvalue

Overlapping copies are an error:

s[0..2] = s[1..3]; // error, overlapping copy
s[1..3] = s[0..2]; // error, overlapping copy

Disallowing overlapping makes it possible for more aggressive parallel code optimizations than possible with the serial semantics of C.

Array Setting

If a slice operator appears as the lvalue of an assignment expression, and the type of the rvalue is the same as the element type of the lvalue, then the lvalue's array contents are set to the rvalue.

int[3] s;
int* p;

s[] = 3;     // same as s[0] = 3, s[1] = 3, s[2] = 3
p[0..2] = 3; // same as p[0] = 3, p[1] = 3

Array Concatenation

The binary operator ~ is the cat operator. It is used to concatenate arrays:

int[] a;
int[] b;
int[] c;

a = b ~ c; // Create an array from the concatenation
           // of the b and c arrays

Many languages overload the + operator to mean concatenation. This confusingly leads to, does:

"10" + 3 + 4

produce the number 17, the string "1034" or the string "107" as the result? It isn't obvious, and the language designers wind up carefully writing rules to disambiguate it - rules that get incorrectly implemented, overlooked, forgotten, and ignored. It's much better to have + mean addition, and a separate operator to be array concatenation.

Similarly, the ~= operator means append, as in:

a ~= b; // a becomes the concatenation of a and b

Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array, so:

a = b;           // a refers to b
a = b ~ c[0..0]; // a refers to a copy of b

Appending does not always create a copy, see setting dynamic array length for details.

Array Operations

Many array operations, also known as vector operations, can be expressed at a high level rather than as a loop. For example, the loop:

T[] a, b;
...
for (size_t i = 0; i < a.length; i++)
  a[i] = b[i] + 4;

assigns to the elements of a the elements of b with 4 added to each. This can also be expressed in vector notation as:

T[] a, b;
...
a[] = b[] + 4;

A vector operation is indicated by the slice operator appearing as the lvalue of an =, +=, -=, *=, /=, %=, ^=, &= or |= operator. The rvalue can be an expression consisting either of an array slice of the same length and type as the lvalue or an expression of the element type of the lvalue, in any combination. The operators supported for vector operations are the binary operators +, -, *, /, %, ^, & and |, and the unary operators - and ~.

The lvalue slice and any rvalue slices must not overlap. The vector assignment operators are evaluated right to left, and the other binary operators are evaluated left to right. All operands are evaluated exactly once, even if the array slice has zero elements in it.

The order in which the array elements are computed is implementation defined, and may even occur in parallel. An application must not depend on this order.

Implementation note: many of the more common vector operations are expected to take advantage of any vector math instructions available on the target computer.

Pointer Arithmetic

int[3] abc;              // static array of 3 ints
int[] def = [ 1, 2, 3 ]; // dynamic array of 3 ints

void dibb(int* array) {
  array[2];     // means same thing as *(array + 2)
  *(array + 2); // get 3rd element
}

void diss(int[] array) {
  array[2];     // ok
  *(array + 2); // error, array is not a pointer
}

void ditt(int[3] array) {
  array[2];     // ok
  *(array + 2); // error, array is not a pointer
}

Rectangular Arrays

Experienced FORTRAN numerics programmers know that multidimensional "rectangular" arrays for things like matrix operations are much faster than trying to access them via pointers to pointers resulting from "array of pointers to array" semantics. For example, the D syntax:

double[][] matrix;

declares matrix as an array of pointers to arrays. (Dynamic arrays are implemented as pointers to the array data.) Since the arrays can have varying sizes (being dynamically sized), this is sometimes called "jagged" arrays. Even worse for optimizing the code, the array rows can sometimes point to each other! Fortunately, D static arrays, while using the same syntax, are implemented as a fixed rectangular layout:

double[3][3] matrix;

declares a rectangular matrix with 3 rows and 3 columns, all contiguously in memory. In other languages, this would be called a multidimensional array and be declared as:

double matrix[3,3];

Array Length

Within the [ ] of a static or a dynamic array, the symbol $ represents the length of the array.

int[4] foo;
int[]  bar = foo;
int*   p = &foo[0];

// These expressions are equivalent:
bar[]
bar[0 .. 4]
bar[0 .. $]
bar[0 .. bar.length]

p[0 .. $]      // '$' is not defined, since p is not an array
bar[0]+$            // '$' is not defined, out of scope of [ ]

bar[$-1] // retrieves last element of the array

Array Properties

Static array properties are:

Static Array Properties
Property | Description
.init | Returns an array literal with each element of the literal being the .init property of the array element type.
.sizeof | Returns the array length multiplied by the number of bytes per array element.
.length | Returns the number of elements in the array. This is a fixed quantity for static arrays. It is of type size_t.
.ptr | Returns a pointer to the first element of the array.
.dup | Create a dynamic array of the same size and copy the contents of the array into it.
.idup | Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. D 2.0 only
.reverse | Reverses in place the order of the elements in the array. Returns the array.
.sort | Sorts in place the order of the elements in the array. Returns the array.

Dynamic array properties are:

Dynamic Array Properties
Property | Description
.init | Returns null.
.sizeof | Returns the size of the dynamic array reference, which is 8 in 32-bit builds and 16 on 64-bit builds.
.length | Get/set number of elements in the array. It is of type size_t.
.ptr | Returns a pointer to the first element of the array.
.dup | Create a dynamic array of the same size and copy the contents of the array into it.
.idup | Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. D 2.0 only
.reverse | Reverses in place the order of the elements in the array. Returns the array.
.sort | Sorts in place the order of the elements in the array. Returns the array.

For the .sort property to work on arrays of class objects, the class definition must define the function: int opCmp(Object). This is used to determine the ordering of the class objects. Note that the parameter is of type Object, not the type of the class.

For the .sort property to work on arrays of structs or unions, the struct or union definition must define the function: int opCmp(ref const S) const. The type S is the type of the struct or union. This function will determine the sort ordering.

Examples:

int* p;
int[3] s;
int[] a;

p.length; // error, length not known for pointer
s.length; // compile time constant 3
a.length; // runtime value

p.dup;    // error, length not known
s.dup;    // creates an array of 3 elements, copies
          // elements s into it
a.dup;    // creates an array of a.length elements, copies
          // elements of a into it

Setting Dynamic Array Length

The .length property of a dynamic array can be set as the lvalue of an = operator:

array.length = 7;

This causes the array to be reallocated in place, and the existing contents copied over to the new array. If the new array length is shorter, the array is not reallocated, and no data is copied. It is equivalent to slicing the array:

array = array[0..7];

If the new array length is longer, the remainder is filled out with the default initializer.

To maximize efficiency, the runtime always tries to resize the array in place to avoid extra copying. It will always do a copy if the new size is larger and the array was not allocated via the new operator or resizing in place would overwrite valid data in the array.

For example:
char[] a = new char[20];
char[] b = a[0..10];
char[] c = a[10..20];
char[] d = a;

b.length = 15; // always reallocates because extending in place would
               // overwrite other data in a.
b[11] = 'x';   // a[11] and c[1] are not affected

d.length = 1;
d.length = 20; // also reallocates, because doing this will overwrite a and
               // c

c.length = 12; // may reallocate in place if space allows, because nothing
               // was allocated after c.
c[5] = 'y';    // may affect contents of a, but not b or d because those
               // were reallocated.

a.length = 25; // This always reallocates because if c extended in place,
               // then extending a would overwrite c.  If c didn't
               // reallocate in place, it means there was not enough space,
               // which will still be true for a.
a[15] = 'z';   // does not affect c, because either a or c has reallocated.

To guarantee copying behavior, use the .dup property to ensure a unique array that can be resized. Also, one may use the phobos .capacity property to determine how many elements can be appended to the array without reallocating.

These issues also apply to appending arrays with the ~= operator. Concatenation using the ~ operator is not affected since it always reallocates.

Resizing a dynamic array is a relatively expensive operation. So, while the following method of filling an array:

int[] array;
while (1) {
  c = getinput();
  if (!c)
    break;
  ++array.length;
  array[array.length - 1] = c;
}

will work, it will be inefficient. A more practical approach would be to minimize the number of resizes:

int[] array;
array.length = 100;        // guess
for (i = 0; ; i++) {
  c = getinput();
  if (!c)
    break;
  if (i == array.length)
    array.length *= 2;
  array[i] = c;
}
array.length = i;

Picking a good initial guess is an art, but you usually can pick a value covering 99% of the cases. For example, when gathering user input from the console - it's unlikely to be longer than 80.

Also, you may wish to utilize the phobos reserve function to pre-allocate array data to use with the append operator.

Functions as Array Properties

If the first parameter to a function is an array, the function can be called as if it were a property of the array:

int[] array;
void foo(int[] a, int x);

foo(array, 3);
array.foo(3);   // means the same thing

Array Bounds Checking

It is an error to index an array with an index that is less than 0 or greater than or equal to the array length. If an index is out of bounds, a RangeError exception is raised if detected at runtime, and an error if detected at compile time. A program may not rely on array bounds checking happening, for example, the following program is incorrect:

try {
  for (i = 0; ; i++) {
    array[i] = 5;
  }
}
catch (RangeError) {
  // terminate loop
}
The loop is correctly written:
for (i = 0; i < array.length; i++) {
  array[i] = 5;
}

Implementation Note: Compilers should attempt to detect array bounds errors at compile time, for example:

int[3] foo;
int x = foo[3]; // error, out of bounds

Insertion of array bounds checking code at runtime should be turned on and off with a compile time switch.

Array Initialization

Default Initialization

  • Pointers are initialized to null.
  • Static array contents are initialized to the default initializer for the array element type.
  • Dynamic arrays are initialized to having 0 elements.
  • Associative arrays are initialized to having 0 elements.

Void Initialization

Void initialization happens when the Initializer for an array is void. What it means is that no initialization is done, i.e. the contents of the array will be undefined. This is most useful as an efficiency optimization. Void initializations are an advanced technique and should only be used when profiling indicates that it matters.

Static Initialization of Statically Allocated Arrays

Static initalizations are supplied by a list of array element values enclosed in [ ]. The values can be optionally preceded by an index and a :. If an index is not supplied, it is set to the previous index plus 1, or 0 if it is the first value.

int[3] a = [ 1:2, 3 ]; // a[0] = 0, a[1] = 2, a[2] = 3

This is most handy when the array indices are given by enums:

enum Color { red, blue, green };

int value[Color.max + 1] =
  [ Color.blue :6,
    Color.green:2,
    Color.red  :5 ];

These arrays are statically allocated when they appear in global scope. Otherwise, they need to be marked with const or static storage classes to make them statically allocated arrays.

Special Array Types

Strings

A string is an array of characters. String literals are just an easy way to write character arrays. String literals are immutable (read only).

char[] str1 = "abc";                // error, "abc" is not mutable
char[] str2 = "abc".dup;            // ok, make mutable copy
immutable(char)[] str3 = "abc";     // ok
immutable(char)[] str4 = str1;      // error, str4 is not mutable
immutable(char)[] str5 = str1.idup; // ok, make immutable copy

The name string is aliased to immutable(char)[], so the above declarations could be equivalently written as:

char[] str1 = "abc";     // error, "abc" is not mutable
char[] str2 = "abc".dup; // ok, make mutable copy
string str3 = "abc";     // ok
string str4 = str1;      // error, str4 is not mutable
string str5 = str1.idup; // ok, make immutable copy

char[] strings are in UTF-8 format. wchar[] strings are in UTF-16 format. dchar[] strings are in UTF-32 format.

Strings can be copied, compared, concatenated, and appended:

str1 = str2;
if (str1 < str3) ...
func(str3 ~ str4);
str4 ~= str1;

with the obvious semantics. Any generated temporaries get cleaned up by the garbage collector (or by using alloca()). Not only that, this works with any array not just a special String array.

A pointer to a char can be generated:

char* p = &str[3]; // pointer to 4th element
char* p = str;     // pointer to 1st element

Since strings, however, are not 0 terminated in D, when transferring a pointer to a string to C, add a terminating 0:

str ~= "\0";

or use the function std.string.toStringz.

The type of a string is determined by the semantic phase of compilation. The type is one of: char[], wchar[], dchar[], and is determined by implicit conversion rules. If there are two equally applicable implicit conversions, the result is an error. To disambiguate these cases, a cast or a postfix of c, w or d can be used:

cast(immutable(wchar) [])"abc" // this is an array of wchar characters
"abc"w                         // so is this

String literals that do not have a postfix character and that have not been cast can be implicitly converted between string, wstring, and dstring as necessary.

char c;
wchar w;
dchar d;

c = 'b';     // c is assigned the character 'b'
w = 'b';     // w is assigned the wchar character 'b'
w = 'bc';    // error - only one wchar character at a time
w = "b"[0];  // w is assigned the wchar character 'b'
w = "\r"[0]; // w is assigned the carriage return wchar character
d = 'd';     // d is assigned the character 'd'

C's printf() and Strings

printf() is a C function and is not part of D. printf() will print C strings, which are 0 terminated. There are two ways to use printf() with D strings. The first is to add a terminating 0, and cast the result to a char*:

str ~= "\0";
printf("the string is '%s'\n", cast(char*)str);

or:

import std.string;
printf("the string is '%s'\n", std.string.toStringz(str));

String literals already have a 0 appended to them, so can be used directly:

printf("the string is '%s'\n", cast(char*)"string literal");

So, why does the first string literal to printf not need the cast? The first parameter is prototyped as a const(char)*, and a string literal can be implicitly cast to a const(char)*. The rest of the arguments to printf, however, are variadic (specified by ...), and a string literal is passed as a (length,pointer) combination to variadic parameters.

The second way is to use the precision specifier. The length comes first, followed by the pointer:

printf("the string is '%.*s'\n", str.length, str.ptr);

The best way is to use std.stdio.writefln, which can handle D strings:

import std.stdio;
writefln("the string is '%s'", str);

Implicit Conversions

A pointer T* can be implicitly converted to one of the following:

  • void*

A static array T[dim] can be implicitly converted to one of the following:

  • T[]
  • const(U)[]
  • void[]

A dynamic array T[] can be implicitly converted to one of the following:

  • const(U)[]
  • void[]

Where U is a base class of T.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Associative Arrays - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Associative Arrays

Associative arrays have an index that is not necessarily an integer, and can be sparsely populated. The index for an associative array is called the key, and its type is called the KeyType.

Associative arrays are declared by placing the KeyType within the [ ] of an array declaration:

int[string] b;    // associative array b of ints that are
                  // indexed by an array of characters.
                  // The KeyType is string
b["hello"] = 3;   // set value associated with key "hello" to 3
func(b["hello"]); // pass 3 as parameter to func()

Particular keys in an associative array can be removed with the remove function:

b.remove("hello");

The InExpression yields a pointer to the value if the key is in the associative array, or null if not:

int* p;
p = ("hello" in b);
if (p !is (B null))
        ...

KeyTypes cannot be functions or voids.

The element types of an associative array cannot be functions or voids.

Using Classes as the KeyType

Classes can be used as the KeyType. For this to work, the class definition must override the following member functions of class Object:

  • hash_t toHash()
  • bool opEquals(Object)
  • int opCmp(Object)

hash_t is an alias to an integral type.

Note that the parameter to opCmp and opEquals is of type Object, not the type of the class in which it is defined.

For example:

class Foo {
  int a, b;

  hash_t toHash() { return a + b; }

  bool opEquals(Object o)
  { Foo foo = cast(Foo) o;
    return foo && a == foo.a && b == foo.b;
  }

  int opCmp(Object o)
  { Foo foo = cast(Foo) o;
    if (!foo)
      return -1;
    if (a == foo.a)
      return b - foo.b;
    return a - foo.a;
  }
}

The implementation may use either opEquals or opCmp or both. Care should be taken so that the results of opEquals and opCmp are consistent with each other when the class objects are the same or not.

Using Structs or Unions as the KeyType

If the KeyType is a struct or union type, a default mechanism is used to compute the hash and comparisons of it based on the binary data within the struct value. A custom mechanism can be used by providing the following functions as struct members:

const hash_t toHash();
const bool opEquals(ref const KeyType s);
const int opCmp(ref const KeyType s);

For example:

import std.string;

struct MyString {
  string str;

  const hash_t toHash()
  { hash_t hash;
    foreach (char c; str)
      hash = (hash * 9) + c;
    return hash;
  }

  const bool opEquals(ref const MyString s)
  {
    return std.string.cmp(this.str, s.str) == 0;
  }

  const int opCmp(ref const MyString s)
  {
    return std.string.cmp(this.str, s.str);
  }
}

The implementation may use either opEquals or opCmp or both. Care should be taken so that the results of opEquals and opCmp are consistent with each other when the struct/union objects are the same or not.

Runtime Initialization of Immutable AAs

Immutable associative arrays are often desirable, but sometimes initialization must be done at runtime. This can be achieved with a constructor (static constructor depending on scope), a buffer associative array and assumeUnique:

immutable long[string] aa;

static this()
{
    import std.exception : assumeUnique;
    import std.conv : to;

    long[string] temp; // mutable buffer
    foreach(i; 0 .. 10)
    {
        temp[to!string(i)] = i;
    }
    temp.rehash; // for faster lookups

    aa = assumeUnique(temp);
}

unittest
{
    assert(aa["1"] == 1);
    assert(aa["5"] == 5);
    assert(aa["9"] == 9);
}

Properties

Properties for associative arrays are:
Associative Array Properties
Property | Description
.sizeof | Returns the size of the reference to the associative array; it is 4 in 32-bit builds and 8 on 64-bit builds.
.length | Returns number of values in the associative array. Unlike for dynamic arrays, it is read-only.
.keys | Returns dynamic array, the elements of which are the keys in the associative array.
.values | Returns dynamic array, the elements of which are the values in the associative array.
.rehash | Reorganizes the associative array in place so that lookups are more efficient. rehash is effective when, for example, the program is done loading up a symbol table and now needs fast lookups in it. Returns a reference to the reorganized array.
.byKey() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the keys of the associative array.
.byValue() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the values of the associative array.
.get(Key key, lazy Value defaultValue) | Looks up key; if it exists returns corresponding value else evaluates and returns defaultValue.

Associative Array Example: word count

Let's consider the file is ASCII encoded with LF EOL. In general case we should use dchar c for iteration over code points and functions from std.uni.

import std.file;         // D file I/O
import std.stdio;
import std.ascii;

void main (string[] args) {
  ulong totalWords, totalLines, totalChars;
  ulong[string] dictionary;

  writefln("   lines   words   bytes file");
  foreach (arg; args[1 .. $]) // for each argument except the first one
  {
    ulong wordCount, lineCount, charCount;

    foreach(line; File(arg).byLine())
    {
      bool inWord;
      size_t wordStart;

      void tryFinishWord(size_t wordEnd)
      {
        if (inWord)
        {
          auto word = line[wordStart .. wordEnd];
          ++dictionary[word.idup];   // increment count for word
          inWord = false;
        }
      }

      foreach (i, char c; line)
      {
        if (std.ascii.isDigit(c))
        { // c is a digit (0..9)
        }
        else if (std.ascii.isAlpha(c))
        { // c is an ASCII letter (A..Z, a..z)
          if (!inWord)
          {
            wordStart = i;
            inWord = true;
            ++wordCount;
          }
        }
        else
          tryFinishWord(i);
        ++charCount;
      }
      tryFinishWord(line.length);
      ++lineCount;
    }

    writefln("%8s%8s%8s %s", lineCount, wordCount, charCount, arg);
    totalWords += wordCount;
    totalLines += lineCount;
    totalChars += charCount;
  }

  if (args.length > 2)
  {
    writefln("-------------------------------------\n%8s%8s%8s total",
            totalLines, totalWords, totalChars);
  }

  writeln("-------------------------------------");
  foreach (word; dictionary.keys.sort)
  {
    writefln("%3s %s", dictionary[word], word);
  }
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Structs, Unions - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Structs, Unions

Whereas classes are reference types, structs are value types. Any C struct can be exactly represented as a D struct, except non-static function-nested D structs which access the context of their enclosing scope. In C++ parlance, a D struct is a POD (Plain Old Data) type, with a trivial constructor and destructor. Structs and unions are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type. External types can be defined by the operating system API, or by a file format. Object oriented features are provided with the class data type.

A struct is defined to not have an identity; that is, the implementation is free to make bit copies of the struct as convenient.

Struct, Class Comparison Table
Feature | struct | class | C struct | C++ struct | C++ class
value type | X |  | X | X | X
reference type |  | X |  |  |
data members | X | X | X | X | X
hidden members | X | X |  | X | X
static members | X | X |  | X | X
default member initializers | X | X |  |  |
bit fields |  |  | X | X | X
non-virtual member functions | X | X |  | X | X
virtual member functions |  | X |  | X | X
constructors | X | X |  | X | X
postblit/copy constructors | X |  |  | X | X
destructors | X | X |  | X | X
SharedStaticConstructors | X | X |  |  |
SharedStaticDestructors | X | X |  |  |
RAII | X | X |  | X | X
assign overload | X |  |  | X | X
literals | X |  |  |  |
operator overloading | X | X |  | X | X
inheritance |  | X |  | X | X
invariants | X | X |  |  |
unit tests | X | X |  |  |
synchronizable |  | X |  |  |
parameterizable | X | X |  | X | X
alignment control | X | X |  |  |
member protection | X | X |  | X | X
default public | X | X | X | X |
tag name space |  |  | X | X | X
anonymous | X |  | X | X | X
static constructor | X | X |  |  |
static destructor | X | X |  |  |
const/immutable/shared | X | X |  |  |
inner nesting | YES | YES |  |  |
AggregateDeclaration:
    struct Identifier StructBody
    union Identifier StructBody
    struct Identifier ;
    union Identifier ;
    StructTemplateDeclaration
    UnionTemplateDeclaration

StructBody:
    { }
    { StructBodyDeclarations }

StructBodyDeclarations:
    StructBodyDeclaration
    StructBodyDeclaration StructBodyDeclarations

StructBodyDeclaration:
    DeclDef
    StructAllocator
    StructDeallocator
    StructPostblit
    AliasThis

StructAllocator:
    ClassAllocator

StructDeallocator:
    ClassDeallocator

They work like they do in C, with the following exceptions:

  • no bit fields
  • alignment can be explicitly specified
  • no separate tag name space - tag names go into the current scope
  • declarations like:
    struct ABC x;
    are not allowed, replace with:
    ABC x;
  • anonymous structs/unions are allowed as members of other structs/unions
  • Default initializers for members can be supplied.
  • Member functions and static members are allowed.

Opaque Structs and Unions

Opaque struct and union declarations do not have a StructBody:

struct S;
union U;

The members are completely hidden to the user, and so the only operations on those types are ones that do not require any knowledge of the contents of those types. For example:

struct S;
S.sizeof; // error, size is not known
S s;      // error, cannot initialize unknown contents
S* p;     // ok, knowledge of members is not necessary

They can be used to implement the PIMPL idiom.

Static Initialization of Structs

Static struct members are by default initialized to whatever the default initializer for the member is, and if none supplied, to the default initializer for the member's type. If a static initializer is supplied, the members are initialized by the member name, colon, expression syntax. The members may be initialized in any order. Initializers for statics must be evaluatable at compile time. Members not specified in the initializer list are default initialized.
struct S { int a; int b; int c; int d = 7;}
static S x = { a:1, b:2};            // c is set to 0, d to 7
static S z = { c:4, b:5, a:2 , d:5}; // z.a = 2, z.b = 5, z.c = 4, z.d = 5
C-style initialization, based on the order of the members in the struct declaration, is also supported:
static S q = { 1, 2 }; // q.a = 1, q.b = 2, q.c = 0, q.d = 7

Struct literals can also be used to initialize statics, but they must be evaluable at compile time.

static S q = S( 1, 2+3 ); // q.a = 1, q.b = 5, q.c = 0, q.d = 7

The static initializer syntax can also be used to initialize non-static variables, provided that the member names are not given. The initializer need not be evaluatable at compile time.

void test(int i) {
  S q = { 1, i }; // q.a = 1, q.b = i, q.c = 0, q.d = 7
}

Static Initialization of Unions

Unions are initialized explicitly.
union U { int a; double b; }
static U u = { b : 5.0 }; // u.b = 5.0
Other members of the union that overlay the initializer, but occupy more storage, have the extra storage initialized to zero.

Dynamic Initialization of Structs

Structs can be dynamically initialized from another value of the same type:

struct S { int a; }
S t;      // default initialized
t.a = 3;
S s = t;  // s.a is set to 3

If opCall is overridden for the struct, and the struct is initialized with a value that is of a different type, then the opCall operator is called:

struct S {
  int a;

  static S opCall(int v)
  { S s;
    s.a = v;
    return s;
  }

  static S opCall(S v)
  { S s;
    s.a = v.a + 1;
    return s;
  }
}

S s = 3; // sets s.a to 3
S t = s; // sets t.a to 3, S.opCall(s) is not called

Struct Literals

Struct literals consist of the name of the struct followed by a parenthesized argument list:

struct S { int x; float y; }

int foo(S s) { return s.x; }

foo( S(1, 2) ); // set field x to 1, field y to 2

Struct literals are syntactically like function calls. If a struct has a member function named opCall, then struct literals for that struct are not possible. It is an error if there are more arguments than fields of the struct. If there are fewer arguments than fields, the remaining fields are initialized with their respective default initializers. If there are anonymous unions in the struct, only the first member of the anonymous union can be initialized with a struct literal, and all subsequent non-overlapping fields are default initialized.

Struct Properties

Struct Properties
.sizeof | Size in bytes of struct
.alignof | Size boundary struct needs to be aligned on
.tupleof | Gets type tuple of fields

Struct Field Properties

Struct Field Properties
.offsetof Offset in bytes of field from beginning of struct

Const and Immutable Structs

A struct declaration can have a storage class of const, immutable or shared. It has an equivalent effect as declaring each member of the struct as const, immutable or shared.

const struct S { int a; int b = 2; }

void main() {
  S s = S(3); // initializes s.a to 3
  S t;        // initializes t.a to 0
  t = s;      // error, t is const
  t.a = 4;    // error, t.a is const
}

Struct Constructors

Struct constructors are used to initialize an instance of a struct. The ParameterList may not be empty. Struct instances that are not instantiated with a constructor are default initialized to their .init value.

struct S {
  int x, y;

  this()  // error, cannot implement default ctor for structs
  {
  }

  this(int a, int b)
  {
    x = a;
    y = b;
  }
}

void main()
{
  S a = S(4, 5);
  auto b = S();  // same as auto b = S.init;
}

Struct Postblits

StructPostblit:
    this(this) FunctionBody

Copy construction is defined as initializing a struct instance from another struct of the same type. Copy construction is divided into two parts:

  1. blitting the fields, i.e. copying the bits
  2. running postblit on the result

The first part is done automatically by the language, the second part is done if a postblit function is defined for the struct. The postblit has access only to the destination struct object, not the source. Its job is to ‘fix up’ the destination as necessary, such as making copies of referenced data, incrementing reference counts, etc. For example:

struct S {
  int[] a;    // array is privately owned by this instance
  this(this) {
    a = a.dup;
  }
  ~this() {
    delete a;
  }
}

Unions may not have fields that have postblits.

Struct Destructors

Destructors are called when an object goes out of scope. Their purpose is to free up resources owned by the struct object.

Unions may not have fields that have destructors.

Assignment Overload

While copy construction takes care of initializing an object from another object of the same type, assignment is defined as copying the contents of one object over another, already initialized, type:

struct S { ... }
S s;      // default construction of s
S t = s;  // t is copy-constructed from s
t = s;    // t is assigned from s

Struct assignment t=s is defined to be semantically equivalent to:

t.opAssign(s);

where opAssign is a member function of S:

S* opAssign(ref const S s)
{   ... bitcopy *this into tmp ...
    ... bitcopy s into *this ...
    ... call destructor on tmp ...
    return this;
}

While the compiler will generate a default opAssign as needed, a user-defined one can be supplied. The user-defined one must still implement the equivalent semantics, but can be more efficient.

One reason a custom opAssign might be more efficient is if the struct has a reference to a local buffer:

struct S {
  int[] buf;
  int a;

  S* opAssign(ref const S s) {
    a = s.a;
    return this;
  }

  this(this) {
    buf = buf.dup;
  }

  ~this() {
    delete buf;
  }
}

Here, S has a temporary workspace buf[]. The normal postblit will pointlessly free and reallocate it. The custom opAssign will reuse the existing storage.

Nested Structs

A nested struct is a struct that is declared inside the scope of a function or a templated struct that has aliases to local functions as a template argument. Nested structs have member functions. It has access to the context of its enclosing scope (via an added hidden field).

void foo() {
  int i = 7;
  struct SS {
    int x,y;
    int bar() { return x + i + 1; }
  }
  SS s;
  s.x = 3;
  s.bar(); // returns 11
}

A struct can be prevented from being nested by using the static attribute, but then of course it will not be able to access variables from its enclosing scope.

void foo() {
  int i = 7;
  static struct SS {
    int x,y;
    int bar() {
      return i; // error, SS is not a nested struct
    }
  }
}

A templated struct can become a nested struct if it has a local function passed as an aliased argument:

struct A(alias F) {
  int fun(int i) { return F(i); }
}

A!(F) makeA(alias F)() {return A!(F)(); }

void main() {
  int x = 40;
  int fun(int i) { return x + i; }
  A!(fun) a = makeA!(fun)();
  a.fun(2);
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Classes - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Classes

The object-oriented features of D all come from classes. The class hierarchy has as its root the class Object. Object defines a minimum level of functionality that each derived class has, and a default implementation for that functionality.

Classes are programmer defined types. Support for classes are what make D an object oriented language, giving it encapsulation, inheritance, and polymorphism. D classes support the single inheritance paradigm, extended by adding support for interfaces. Class objects are instantiated by reference only.

A class can be exported, which means its name and all its non-private members are exposed externally to the DLL or EXE.

A class declaration is defined:

ClassDeclaration:
    class Identifier BaseClassListopt ClassBody
    ClassTemplateDeclaration

BaseClassList:
    : SuperClass
    : SuperClass , Interfaces
    : Interfaces

SuperClass:
    Identifier

Interfaces:
    Interface
    Interface , Interfaces

Interface:
    Identifier

ClassBody:
    { }
    { ClassBodyDeclarations }

ClassBodyDeclarations:
    ClassBodyDeclaration
    ClassBodyDeclaration ClassBodyDeclarations

ClassBodyDeclaration:
    DeclDef
    Invariant
    ClassAllocator
    ClassDeallocator
Classes consist of:
  • a super class
  • interfaces
  • dynamic fields
  • static fields
  • types
  • member functions
    • static member functions
    • Virtual Functions
    • Synchronized Functions
    • Constructors
    • Destructors
    • Static Constructors
    • Static Destructors
    • SharedStaticConstructors
    • SharedStaticDestructors
    • Class Invariants
    • Unit Tests
    • Class Allocators
    • Class Deallocators
    • Alias This
A class is defined:
class Foo {
  ... members ...
}
Note that there is no trailing ; after the closing } of the class definition. It is also not possible to declare a variable var like:
class Foo { } var;
Instead:
class Foo { }
Foo var;

Access Control

Access to class members is controlled using ProtectionAttributes. The default protection attribute is public. Access control does not affect visibility.

Fields

Class members are always accessed with the . operator.

Members of a base class can be accessed by prepending the name of the base class followed by a dot:

class A { int a; }
class B : A { int a; }

void foo(B b) {
  b.a = 3;   // accesses field B.a
  b.A.a = 4; // accesses field A.a

The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes.

Field Properties

The .offsetof property gives the offset in bytes of the field from the beginning of the class instantiation. .offsetof can only be applied to expressions which produce the type of the field itself, not the class type:

class Foo {
  int x;
}
...
void test(Foo foo) {
  size_t o;

  o = Foo.x.offsetof; // error, Foo.x needs a 'this' reference
  o = foo.x.offsetof; // ok
}

Class Properties

The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.

class Foo { int x; long y; }
void test(Foo foo) {
  foo.tupleof[0] = 1; // set foo.x to 1
  foo.tupleof[1] = 2; // set foo.y to 2
  foreach (x; foo.tupleof)
    writef(x);        // prints 12
}

The properties .__vptr and .__monitor give access to the class object's vtbl[] and monitor, respectively, but should not be used in user code.

Super Class

All classes inherit from a super class. If one is not specified, it inherits from Object. Object forms the root of the D class inheritance hierarchy.

Member Functions

Non-static member functions have an extra hidden parameter called this through which the class object's other members can be accessed.

Non-static member functions can have, in addition to the usual FunctionAttributes, the attributes const, immutable, shared, or inout. These attributes apply to the hidden this parameter.

class C {
  int a;
  const void foo() {
    a = 3; // error, 'this' is const
  }
  void foo() immutable {
    a = 3; // error, 'this' is immutable
  }

Synchronized Functions

Synchronized class member functions have the storage class synchronized. A static member function is synchronized on the classinfo object for the class, which means that one monitor is used for all static synchronized member functions for that class. For non-static synchronized functions, the monitor used is part of the class object. For example:

class Foo {
  synchronized void bar() { ...statements... }
}

is equivalent to (as far as the monitors go):

class Foo {
  void bar() {
    synchronized (this) { ...statements... }
  }
}

Structs do not have synchronized member functions.

Constructors

Constructor:
        this Parameters FunctionBody
        TemplatedConstructor

Members are always initialized to the default initializer for their type, which is usually 0 for integer types and NAN for floating point types. This eliminates an entire class of obscure problems that come from neglecting to initialize a member in one of the constructors. In the class definition, there can be a static initializer to be used instead of the default:

class Abc {
  int a;      // default initializer for a is 0
  long b = 7; // default initializer for b is 7
  float f;    // default initializer for f is NAN
}
This static initialization is done before any constructors are called.

Constructors are defined with a function name of this and having no return value:

class Foo {
  this(int x)  // declare constructor for Foo
  {   ...
  }
  this()
  {   ...
  }
}
Base class construction is done by calling the base class constructor by the name super:
class A { this(int y) { } }

class B : A {
  int j;
  this() {
    ...
    super(3);  // call base constructor A.this(3)
    ...
  }
}

Constructors can also call other constructors for the same class in order to share common initializations (this is called delegating constructors):

class C {
  int j;
  this() {
    ...
  }
  this(int i) {
    this();
    j = i;
  }
}
If no call to constructors via this or super appear in a constructor, and the base class has a constructor, a call to super() is inserted at the beginning of the constructor.

If there is no constructor for a class, but there is a constructor for the base class, a default constructor of the form:

this() { }

is implicitly generated.

Class object construction is very flexible, but some restrictions apply:

  1. It is illegal for constructors to mutually call each other, although the compiler is not required to detect it. It will result in undefined behavior.
    this() { this(1); }
this(int i) { this(); } // illegal, cyclic constructor calls
  2. If any constructor call appears inside a constructor, any path through the constructor must make exactly one constructor call:
    this()  { a || super(); }       // illegal

this() { (a) ? this(1) : super(); }     // ok

this() {
  for (...) {
    super();  // illegal, inside loop
  }
}
  3. It is illegal to refer to this implicitly or explicitly prior to making a constructor call.
  4. Constructor calls cannot appear after labels (in order to make it easy to check for the previous conditions in the presence of goto's).

Instances of class objects are created with NewExpressions:

A a = new A(3);

The following steps happen:

  1. Storage is allocated for the object. If this fails, rather than return null, an OutOfMemoryError is thrown. Thus, tedious checks for null references are unnecessary.
  2. The raw data is statically initialized using the values provided in the class definition. The pointer to the vtbl[] (the array of pointers to virtual functions) is assigned. This ensures that constructors are passed fully formed objects for which virtual functions can be called. This operation is equivalent to doing a memory copy of a static version of the object onto the newly allocated one, although more advanced compilers may be able to optimize much of this away.
  3. If there is a constructor defined for the class, the constructor matching the argument list is called.
  4. If class invariant checking is turned on, the class invariant is called at the end of the constructor.

Destructors

Destructor:
    ~ this ( ) FunctionBody
The garbage collector calls the destructor function when the object is deleted. The syntax is:
class Foo {
  ~this() // destructor for Foo
  {
  }
}

There can be only one destructor per class, the destructor does not have any parameters, and has no attributes. It is always virtual.

The destructor is expected to release any resources held by the object.

The program can explicitly inform the garbage collector that an object is no longer referred to (with the delete expression), and then the garbage collector calls the destructor immediately, and adds the object's memory to the free storage. The destructor is guaranteed to never be called twice.

The destructor for the super class automatically gets called when the destructor ends. There is no way to call the super destructor explicitly.

The garbage collector is not guaranteed to run the destructor for all unreferenced objects. Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. This means that destructors cannot reference sub objects. This rule does not apply to auto objects or objects deleted with the DeleteExpression, as the destructor is not being run by the garbage collector, meaning all references are valid.

Objects referenced from the data segment never get collected by the gc.

Static Constructors

StaticConstructor:
    static this ( ) FunctionBody

A static constructor is a function that performs initializations of thread local data before the main() function gets control for the main thread, and upon thread startup. Static constructors are used to initialize static class members with values that cannot be computed at compile time.

Static constructors in other languages are built implicitly by using member initializers that can't be computed at compile time. The trouble with this stems from not having good control over exactly when the code is executed, for example:

class Foo {
  static int a = b + 1;
  static int b = a * 2;
}
What values do a and b end up with, what order are the initializations executed in, what are the values of a and b before the initializations are run, is this a compile error, or is this a runtime error? Additional confusion comes from it not being obvious if an initializer is static or dynamic.

D makes this simple. All member initializations must be determinable by the compiler at compile time, hence there is no order-of-evaluation dependency for member initializations, and it is not possible to read a value that has not been initialized. Dynamic initialization is performed by a static constructor, defined with a special syntax static this().

class Foo {
  static int a;         // default initialized to 0
  static int b = 1;
  static int c = b + a; // error, not a constant initializer

  static this()    // static constructor
  {
    a = b + 1;          // a is set to 2
    b = a * 2;          // b is set to 4
  }
}

If main() or the thread returns normally, (does not throw an exception), the static destructor is added to the list of functions to be called on thread termination. Static constructors have empty parameter lists.

Static constructors within a module are executed in the lexical order in which they appear. All the static constructors for modules that are directly or indirectly imported are executed before the static constructors for the importer.

The static in the static constructor declaration is not an attribute, it must appear immediately before the this:

class Foo {
  static this() { ... } // a static constructor
  static private this() { ... } // not a static constructor
  static {
    this() { ... }      // not a static constructor
  }
  static:
    this() { ... }      // not a static constructor
}

Static Destructors

StaticDestructor:
    static ~ this ( ) FunctionBody
A static destructor is defined as a special static function with the syntax static ~this().
class Foo {
  static ~this() // static destructor
  {
  }
}

A static destructor gets called on thread termination, but only if the static constructor completed successfully. Static destructors have empty parameter lists. Static destructors get called in the reverse order that the static constructors were called in.

The static in the static destructor declaration is not an attribute, it must appear immediately before the ~this:

class Foo {
  static ~this() { ... }  // a static destructor
  static private ~this() { ... } // not a static destructor
  static
  {
    ~this() { ... }  // not a static destructor
  }
  static:
    ~this() { ... }  // not a static destructor
}

Shared Static Constructors

SharedStaticConstructor:
    shared static this ( ) FunctionBody

Shared static constructors are executed before any StaticConstructors, and are intended for initializing any shared global data.

Shared Static Destructors

SharedStaticDestructor:
    shared static ~ this ( ) FunctionBody

Shared static destructors are executed at program termination in the reverse order that SharedStaticConstructors were executed.

Class Invariants

Invariant:
    invariant ( ) BlockStatement
Class invariants are used to specify characteristics of a class that always must be true (except while executing a member function). They are described in Invariants.

Class Allocators

Note: Class allocators are deprecated in D2.
ClassAllocator:
    new Parameters FunctionBody
A class member function of the form:
new(uint size) {
  ...
}
is called a class allocator. The class allocator can have any number of parameters, provided the first one is of type uint. Any number can be defined for a class, the correct one is determined by the usual function overloading rules. When a new expression:
new Foo;
is executed, and Foo is a class that has an allocator, the allocator is called with the first argument set to the size in bytes of the memory to be allocated for the instance. The allocator must allocate the memory and return it as a void*. If the allocator fails, it must not return a null, but must throw an exception. If there is more than one parameter to the allocator, the additional arguments are specified within parentheses after the new in the NewExpression:
class Foo {
  this(char[] a) { ... }

  new(uint size, int x, int y) {
    ...
  }
}

...

new(1,2) Foo(a);        // calls new(Foo.sizeof,1,2)

Derived classes inherit any allocator from their base class, if one is not specified.

The class allocator is not called if the instance is created on the stack.

See also Explicit Class Instance Allocation.

Class Deallocators

Note: Class deallocators and the delete operator are deprecated in D2. Use the destroy function to finalize an object by calling its destructor. The memory of the object is not immediately deallocated, instead the GC will collect the memory of the object at an undetermined point after finalization:
class Foo { int x; this() { x = 1; } }
Foo foo = new Foo;
destroy(foo);
assert(foo.x == int.init);  // object is still accessible

ClassDeallocator:
    delete Parameters FunctionBody
A class member function of the form:
delete(void *p) {
  ...
}
is called a class deallocator. The deallocator must have exactly one parameter of type void*. Only one can be specified for a class. When a delete expression:
delete f;

is executed, and f is a reference to a class instance that has a deallocator, the deallocator is called with a pointer to the class instance after the destructor (if any) for the class is called. It is the responsibility of the deallocator to free the memory.

Derived classes inherit any deallocator from their base class, if one is not specified.

The class allocator is not called if the instance is created on the stack.

See also Explicit Class Instance Allocation.

Alias This

AliasThis:
    alias Identifier this;

An AliasThis declaration names a member to subtype. The Identifier names that member.

A class or struct can be implicitly converted to the AliasThis member.

struct S {
  int x;
  alias x this;
}

int foo(int i) { return i * 2; }

void test() {
  S s;
  s.x = 7;
  int i = -s;  // i == -7
  i = s + 8;   // i == 15
  i = s + s;   // i == 14
  i = 9 + s;   // i == 16
  i = foo(s);  // implicit conversion to int
}

If the member is a class or struct, undefined lookups will be forwarded to the AliasThis member.

struct Foo
{
  int baz = 4;
  int get() { return 7; }
}

class Bar
{
  Foo foo;
  alias foo this;
}

void test() {
  auto bar = new Bar;
  int i = bar.baz; // i == 4
  i = bar.get(); // i == 7
}

If the Identifier refers to a property member function with no parameters, conversions and undefined lookups are forwarded to the return value of the function.

struct S
{
  int x;
  @property int get() {
    return x * 2;
  }
  alias get this;
}

void test() {
  S s;
  s.x = 2;
  int i = s; // i == 4
}

Multiple AliasThis are allowed. For implicit conversions and forwarded lookups, all AliasThis declarations are attempted; if more than one AliasThis is eligible, the ambiguity is disallowed by raising an error. Note: Multiple AliasThis is currently unimplemented.

Scope Classes

A scope class is a class with the scope attribute, as in:
scope class Foo { ... }
The scope characteristic is inherited, so if any classes derived from a scope class are also scope.

An scope class reference can only appear as a function local variable. It must be declared as being scope:

scope class Foo { ... }

void func() {
  Foo f;    // error, reference to scope class must be scope
  scope Foo g = new Foo(); // correct
}
When an scope class reference goes out of scope, the destructor (if any) for it is automatically called. This holds true even if the scope was exited via a thrown exception.

Final Classes

Final classes cannot be subclassed:

final class A { }
class B : A { }  // error, class A is final

Nested Classes

A nested class is a class that is declared inside the scope of a function or another class. A nested class has access to the variables and other symbols of the classes and functions it is nested inside:
class Outer {
  int m;

  class Inner {
    int foo() {
      return m;   // Ok to access member of Outer
    }
  }
}

void func() {
  int m;

  class Inner {
    int foo() {
      return m; // Ok to access local variable m of func()
    }
  }
}
If a nested class has the static attribute, then it can not access variables of the enclosing scope that are local to the stack or need a this:
class Outer {
  int m;
  static int n;

  static class Inner {
    int foo() {
      return m;   // Error, Inner is static and m needs a this
      return n;   // Ok, n is static
    }
  }
}

void func() {
  int m;
  static int n;

  static class Inner {
    int foo() {
      return m;   // Error, Inner is static and m is local to the stack
      return n;   // Ok, n is static
    }
  }
}
Non-static nested classes work by containing an extra hidden member (called the context pointer) that is the frame pointer of the enclosing function if it is nested inside a function, or the this of the enclosing class's instance if it is nested inside a class.

When a non-static nested class is instantiated, the context pointer is assigned before the class's constructor is called, therefore the constructor has full access to the enclosing variables. A non-static nested class can only be instantiated when the necessary context pointer information is available:

class Outer {
  class Inner { }

  static class SInner { }
}

void func() {
  class Nested { }

  Outer o = new Outer;        // Ok
  Outer.Inner oi = new Outer.Inner;   // Error, no 'this' for Outer
  Outer.SInner os = new Outer.SInner; // Ok

  Nested n = new Nested;      // Ok
}

A this can be supplied to the creation of an inner class instance by prefixing it to the NewExpression:

class Outer {
  int a;

  class Inner {
    int foo() {
      return a;
    }
  }
}

int bar() {
  Outer o = new Outer;
  o.a = 3;
  Outer.Inner oi = o.new Inner;
  return oi.foo();    // returns 3
}

Here o supplies the this to the outer class instance of Outer.

The property .outer used in a nested class gives the this pointer to its enclosing class. If the enclosing context is not a class, the .outer will give the pointer to it as a void* type.

class Outer {
  class Inner {
    Outer foo() {
      return this.outer;
    }
  }

  void bar() {
    Inner i = new Inner;
    assert(this == i.foo());
  }
}

void test() {
  Outer o = new Outer;
  o.bar();
}

Anonymous Nested Classes

An anonymous nested class is both defined and instantiated with a NewAnonClassExpression:

NewAnonClassExpression:
    new AllocatorArgumentsopt class ClassArgumentsopt SuperClassopt Interfacesopt ClassBody

ClassArguments:
    ( ArgumentListopt )

which is equivalent to:

class Identifier : SuperClass Interfaces
        ClassBody

new (ArgumentList) Identifier (ArgumentList);

where Identifier is the name generated for the anonymous nested class.

Const, Immutable and Shared Classes

If a ClassDeclaration has a const, immutable or shared storage class, then it is as if each member of the class was declared with that storage class. If a base class is const, immutable or shared, then all classes derived from it are also const, immutable or shared.

)
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Interfaces - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Interfaces

InterfaceDeclaration:
    interface Identifier BaseInterfaceListopt InterfaceBody
    InterfaceTemplateDeclaration

BaseInterfaceList:
    : InterfaceClasses

InterfaceBody:
    { DeclDefsopt }

Interfaces describe a list of functions that a class that inherits from the interface must implement. A class that implements an interface can be converted to a reference to that interface.

Some operating system objects, like COM/OLE/ActiveX for Win32, have specialized interfaces. D interfaces that are compatible with COM/OLE/ActiveX are called COM Interfaces.

C++ Interfaces are another form of interfaces, meant to be binary compatible with C++.

Interfaces cannot derive from classes; only from other interfaces. Classes cannot derive from an interface multiple times.

interface D
{
    void foo();
}

class A : D, D	// error, duplicate interface
{
}
An instance of an interface cannot be created.
interface D
{
    void foo();
}

...

D d = new D();		// error, cannot create instance of interface

Virtual interface member functions do not have implementations. Interfaces are expected to implement static or final functions.

interface D
{
    void bar() { }	// error, implementation not allowed
    static void foo() { } // ok
    final void abc() { } // ok
}

Classes that inherit from an interface may not override final or static interface member functions.

interface D {
    void bar();
    static void foo() { }
    final void abc() { }
}

class C : D {
    void bar() { } // ok
    void foo() { } // error, cannot override static D.foo()
    void abc() { } // error, cannot override final D.abc()
}

All interface functions must be defined in a class that inherits from that interface:

interface D
{
    void foo();
}

class A : D
{
    void foo() { }	// ok, provides implementation
}

class B : D
{
    int foo() { }	// error, no void foo() implementation
}
Interfaces can be inherited and functions overridden:
interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A
{
    int foo() { return 2; }
}

...

B b = new B();
b.foo();		// returns 2
D d = cast(D) b;	// ok since B inherits A's D implementation
d.foo();		// returns 2;

Interfaces can be reimplemented in derived classes:

interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, D
{
    int foo() { return 2; }
}

...

B b = new B();
b.foo();		// returns 2
D d = cast(D) b;
d.foo();		// returns 2
A a = cast(A) b;
D d2 = cast(D) a;
d2.foo();		// returns 2, even though it is A's D, not B's D

A reimplemented interface must implement all the interface functions, it does not inherit them from a super class:

interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, D
{
}		// error, no foo() for interface D

Interfaces with Contracts

Interface member functions can have contracts even though there is no body for the function. The contracts are inherited by any class member function that implements that interface member function.

interface I
{
    int foo(int i)
      in { assert(i > 7); }
      out (result) { assert(result & 1); }

    void bar();
}

Const and Immutable Interfaces

If an interface has const or immutable storage class, then all members of the interface are const or immutable. This storage class is not inherited.

COM Interfaces

A variant on interfaces is the COM interface. A COM interface is designed to map directly onto a Windows COM object. Any COM object can be represented by a COM interface, and any D object with a COM interface can be used by external COM clients.

A COM interface is defined as one that derives from the interface std.c.windows.com.IUnknown. A COM interface differs from a regular D interface in that:

  • It derives from the interface std.c.windows.com.IUnknown.
  • It cannot be the argument of a DeleteExpression.
  • References cannot be upcast to the enclosing class object, nor can they be downcast to a derived interface. To accomplish this, an appropriate QueryInterface() would have to be implemented for that interface in standard COM fashion.
  • Classes derived from COM interfaces are COM classes.
  • The default linkage for member functions of COM classes is extern(System).
  • The first member of the vtbl[] is not the pointer to the InterfaceInfo, but the first virtual function pointer.

For more information, see Modern COM Programming in D

C++ Interfaces

C++ interfaces are interfaces declared with C++ linkage:

extern (C++) interface Ifoo
{
    void foo();
    void bar();
}

which is meant to correspond with the following C++ declaration:

class Ifoo
{
    virtual void foo();
    virtual void bar();
};

Any interface that derives from a C++ interface is also a C++ interface. A C++ interface differs from a D interface in that:

  • It cannot be the argument of a DeleteExpression.
  • References cannot be upcast to the enclosing class object, nor can they be downcast to a derived interface.
  • The C++ calling convention is the default convention for its member functions, rather than the D calling convention.
  • The first member of the vtbl[] is not the pointer to the Interface, but the first virtual function pointer.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Enums - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Enums

EnumDeclaration:
    enum EnumTag EnumBody
    enum EnumBody
    enum EnumTag : EnumBaseType EnumBody
    enum : EnumBaseType EnumBody

EnumTag:
    Identifier

EnumBaseType:
    Type

EnumBody:
    EmptyEnumBody
    EnumMembersBody

EmptyEnumBody:
    ;

EnumMembersBody:
    { EnumMembers }

EnumMembers:
    EnumMember
    EnumMember ,
    EnumMember , EnumMembers

EnumMember:
    Identifier
    Identifier = AssignExpression
    Type = AssignExpression

Enum declarations are used to define a group of constants. They come in two forms:

  1. Named enums, which have an EnumTag.
  2. Anonymous enums, which do not have an EnumTag.

Named Enums

Named enums are used to declare related constants and group them by giving them a unique type. The EnumMembers are declared in the scope of the enum EnumTag. The enum EnumTag declares a new type, and all the EnumMembers have that type.

This defines a new type X which has values X.A=0, X.B=1, X.C=2:

enum X { A, B, C }	// named enum

If the EnumBaseType is not explicitly set, and the first EnumMember has an initializer, it is set to the type of that initializer. Otherwise, it defaults to type int.

Named enum members may not have individual Types.

A named enum member can be implicitly cast to its EnumBaseType, but EnumBaseType types cannot be implicitly cast to an enum type.

The value of an EnumMember is given by its initializer. If there is no initializer, it is given the value of the previous EnumMember + 1. If it is the first EnumMember, it's value is 0.

An EmptyEnumBody signifies an opaque enum - the enum members are unknown.

Enum Default Initializer

The .init property of an enum type is the value of the first member of that enum. This is also the default initializer for the enum type.

enum X { A=3, B, C }
X x;      // x is initialized to 3

Enum Properties

Enum properties only exist for named enums.

.init | First enum member value
.min | Smallest value of enum
.max | Largest value of enum
.sizeof | Size of storage for an enumerated value

For example:

enum X { A=3, B, C }
X.min    // is X.A
X.max    // is X.C
X.sizeof // is same as int.sizeof

The EnumBaseType of named enums must support comparison in order to compute the .max and .min properties.

Anonymous Enums

If the enum Identifier is not present, then the enum is an anonymous enum, and the EnumMembers are declared in the scope the EnumDeclaration appears in. No new type is created; the EnumMembers have the type of the EnumBaseType.

The EnumBaseType is the underlying type of the enum.

If omitted, the EnumMembers can have different types. Those types are given by the first of:

  1. The Type, if present.
  2. The type of the AssignExpression, if present.
  3. The type of the previous EnumMember, if present.
  4. int
enum { A, B, C }	// anonymous enum

Defines the constants A=0, B=1, C=2, all of type int.

Enums must have at least one member.

The value of an EnumMember is given by its initializer. If there is no initializer, it is given the value of the previous EnumMember + 1. If it is the first EnumMember, it's value is 0.

enum { A, B = 5+7, C, D = 8+C, E }

Sets A=0, B=12, C=13, D=21, and E=22, all of type int.

enum : long { A = 3, B }

Sets A=3, B=4 all of type long.

enum : string {
  A = "hello",
  B = "betty",
  C     // error, cannot add 1 to "betty"
}

enum {
  A = 1.2f,  // A is 1.2f of type float
  B,         // B is 2.2f of type float
  int C = 3, // C is 3 of type int
  D          // D is 4 of type int
}

Manifest Constants

If there is only one member of an anonymous enum, the { } can be omitted:

enum i = 4;      // i is 4 of type int
enum long l = 3; // l is 3 of type long

Such declarations are not lvalues, meaning their address cannot be taken.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Const and Immutable - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Const and Immutable

When examining a data structure or interface, it is very helpful to be able to easily tell which data can be expected to not change, which data might change, and who may change that data. This is done with the aid of the language typing system. Data can be marked as const or immutable, with the default being changeable (or mutable).

immutable applies to data that cannot change. Immutable data values, once constructed, remain the same for the duration of the program's execution. Immutable data can be placed in ROM (Read Only Memory) or in memory pages marked by the hardware as read only. Since immutable data does not change, it enables many opportunities for program optimization, and has applications in functional style programming.

const applies to data that cannot be changed by the const reference to that data. It may, however, be changed by another reference to that same data. Const finds applications in passing data through interfaces that promise not to modify them.

Both immutable and const are transitive, which means that any data reachable through an immutable reference is also immutable, and likewise for const.

Immutable Storage Class

The simplest immutable declarations use it as a storage class. It can be used to declare manifest constants.

immutable int x = 3;  // x is set to 3
x = 4;        // error, x is immutable
char[x] s;    // s is an array of 3 char's

The type can be inferred from the initializer:

immutable y = 4; // y is of type int
y = 5;           // error, y is immutable

If the initializer is not present, the immutable can be initialized from the corresponding constructor:

immutable int z;
void test() {
  z = 3; // error, z is immutable
}
static this() {
  z = 3; // ok, can set immutable that doesn't
         // have static initializer
}

The initializer for a non-local immutable declaration must be evaluatable at compile time:

int foo(int f) { return f * 3; }
int i = 5;
immutable x = 3 * 4;      // ok, 12
immutable y = i + 1;      // error, cannot evaluate at compile time
immutable z = foo(2) + 1; // ok, foo(2) can be evaluated at compile time, 7

The initializer for a non-static local immutable declaration is evaluated at run time:

int foo(int f)
{
  immutable x = f + 1;  // evaluated at run time
  x = 3;                // error, x is immutable
}

Because immutable is transitive, data referred to by an immutable is also immutable:

immutable char[] s = "foo";
s[0] = 'a';  // error, s refers to immutable data
s = "bar";   // error, s is immutable

Immutable declarations can appear as lvalues, i.e. they can have their address taken, and occupy storage.

Const Storage Class

A const declaration is exactly like an immutable declaration, with the following differences:

  • Any data referenced by the const declaration cannot be changed from the const declaration, but it might be changed by other references to the same data.
  • The type of a const declaration is itself const.

Immutable Type

Data that will never change its value can be typed as immutable. The immutable keyword can be used as a type constructor:

immutable(char)[] s = "hello";

The immutable applies to the type within the following parentheses. So, while s can be assigned new values, the contents of s[] cannot be:

s[0] = 'b';  // error, s[] is immutable
s = null;    // ok, s itself is not immutable

Immutableness is transitive, meaning it applies to anything that can be referenced from the immutable type:

immutable(char*)** p = ...;
p = ...;        // ok, p is not immutable
*p = ...;       // ok, *p is not immutable
**p = ...;      // error, **p is immutable
***p = ...;     // error, ***p is immutable

Immutable used as a storage class is equivalent to using immutable as a type constructor for the entire type of a declaration:

immutable int x = 3;   // x is typed as immutable(int)
immutable(int) y = 3;  // y is immutable

Creating Immutable Data

The first way is to use a literal that is already immutable, such as string literals. String literals are always immutable.

auto s = "hello";   // s is immutable(char)[5]
char[] p = "world"; // error, cannot implicitly convert immutable
            // to mutable

The second way is to cast data to immutable. When doing so, it is up to the programmer to ensure that no other mutable references to the same data exist.

char[] s = ...;
immutable(char)[] p = cast(immutable)s;     // undefined behavior
immutable(char)[] p = cast(immutable)s.dup; // ok, unique reference

The .idup property is a convenient way to create an immutable copy of an array:

auto p = s.idup;
p[0] = ...;	  // error, p[] is immutable

Removing Immutable With A Cast

The immutable type can be removed with a cast:

immutable int* p = ...;
int* q = cast(int*)p;

This does not mean, however, that one can change the data:

*q = 3; // allowed by compiler, but result is undefined behavior

The ability to cast away immutable-correctness is necessary in some cases where the static typing is incorrect and not fixable, such as when referencing code in a library one cannot change. Casting is, as always, a blunt and effective instrument, and when using it to cast away immutable-correctness, one must assume the responsibility to ensure the immutableness of the data, as the compiler will no longer be able to statically do so.

Immutable Member Functions

Immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as:

struct S {
  int x;

  void foo() immutable {
    x = 4;      // error, x is immutable
    this.x = 4; // error, x is immutable
  }
}

Note that using immutable on the left hand side of a method does not apply to the return type:

struct S {
  immutable int[] bar()  // bar is still immutable, return type is not!
  {
  }
}

To make the return type immutable, you need to surround the return type with parentheses:

struct S {
  immutable(int[]) bar()  // bar is now mutable, return type is immutable.
  {
  }
}

To make both the return type and the method immutable, you can write:

struct S {
  immutable(int[]) bar() immutable
  {
  }
}

Const Type

Const types are like immutable types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.

Const Member Functions

Const member functions are functions that are not allowed to change any part of the object through the member function's this reference.

Implicit Conversions

Mutable and immutable types can be implicitly converted to const. Mutable types cannot be implicitly converted to immutable, and vice versa.

Comparing D Immutable and Const with C++ Const

Const, Immutable Comparison
Feature | D | C++98
const keyword | Yes | Yes
immutable keyword | Yes | No
const notation Functional:
//ptr to const ptr to const int
const(int*)* p;
Postfix:
//ptr to const ptr to const int
const int *const *p;
transitive const Yes:
//const ptr to const ptr to const int
const int** p;
**p = 3; // error
No:
// const ptr to ptr to int
int** const p;
**p = 3;    // ok
cast away const Yes:
// ptr to const int
const(int)* p;
int* q = cast(int*)p; // ok
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p; //ok
modification after casting away const No:
// ptr to const int
const(int)* p;
int* q = cast(int*)p;
*q = 3;   // undefined behavior
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p;
*q = 3;   // ok
overloading of top level const Yes:
void foo(int x);
void foo(const int x);  //ok
No:
void foo(int x);
void foo(const int x);  //error
aliasing of const with mutable Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
aliasing of immutable with mutable No:
void foo(immutable int* x, int* y) {
 bar(*x); // bar(3)
 *y = 4;  // undefined behavior
 bar(*x); // bar(??)
}
...
int i = 3;
foo(cast(immutable)&i, &i);
No immutables
type of string literal | immutable(char)[] | const char*
implicit conversion of string literal to non-const | not allowed | allowed, but deprecated
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Functions - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Functions

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

Function Return Values

Function return values are considered to be rvalues. This means they cannot be passed by reference to other functions.

Functions Without Bodies

Functions without bodies:

int foo();

that are not declared as abstract are expected to have their implementations elsewhere, and that implementation will be provided at the link step. This enables an implementation of a function to be completely hidden from the user of it, and the implementation may be in another language such as C, assembler, etc.

Pure Functions

Pure functions are functions which cannot access global or static, mutable state save through their arguments. This can enable optimizations based on the fact that a pure function is guaranteed to mutate nothing which isn't passed to it, and in cases where the compiler can guarantee that a pure function cannot alter its arguments, it can enable full, functional purity (i.e. the guarantee that the function will always return the same result for the same arguments). To that end, a pure function:

  • does not read or write any global or static mutable state
  • cannot call functions that are not pure
  • can override an impure function, but an impure function cannot override a pure one
  • is covariant with an impure function
  • cannot perform I/O

As a concession to practicality, a pure function can:

  • allocate memory via a NewExpression
  • terminate the program
  • read and write the floating point exception flags
  • read and write the floating point mode flags, as long as those flags are restored to their initial state upon function entry
  • perform impure operations in statements that are in a ConditionalStatement controlled by a DebugCondition.

A pure function can throw exceptions.

import std.stdio;
int x;
immutable int y;
const int* pz;

pure int foo(int i,
             char* p,
             const char* q,
             immutable int* s)
{
  debug writeln("in foo()"); // ok, impure code allowed in debug statement
  x = i;   // error, modifying global state
  i = x;   // error, reading mutable global state
  i = y;   // ok, reading immutable global state
  i = *pz; // error, reading const global state
  return i;
}

Nothrow Functions

Nothrow functions do not throw any exceptions derived from class Exception.

Nothrow functions are covariant with throwing ones.

Ref Functions

Ref functions allow functions to return by reference. This is analogous to ref function parameters.

ref int foo() {
  auto p = new int;
  return *p;
}
...
foo() = 3;  // reference returns can be lvalues

Auto Functions

Auto functions have their return type inferred from any ReturnStatements in the function body.

An auto function is declared without a return type. If it does not already have a storage class, use the auto storage class.

If there are multiple ReturnStatements, the types of them must match exactly. If there are no ReturnStatements, the return type is inferred to be void.

auto foo(int i) {
  return i + 3;  // return type is inferred to be int
}

Auto Ref Functions

Auto ref functions infer their return type just as auto functions do. In addition, they become ref functions if the return expression is an lvalue, and it would not be a reference to a local or a parameter.

auto ref foo(int x)     { return x; }  // value return
auto ref foo()          { return 3; }  // value return
auto ref foo(ref int x) { return x; }  // ref return
auto ref foo(out int x) { return x; }  // ref return
auto ref foo() { static int x; return x; }  // ref return

The lexically first ReturnStatement determines the ref-ness of a function:

auto ref foo(ref int x) { return 3; return x; }  // ok, value return
auto ref foo(ref int x) { return x; return 3; }  // error, ref return, 3 is not an lvalue

Inout Functions

Functions that deal with mutable, const, or immutable types with equanimity often need to transmit their type to the return value:

int[] foo(int[] a, int x, int y) { return a[x .. y]; }

const(int)[] foo(const(int)[] a, int x, int y) { return a[x .. y]; }

immutable(int)[] foo(immutable(int)[] a, int x, int y) { return a[x .. y]; }

The code generated by these three functions is identical. To indicate that these can be one function, the inout type constructor is employed:

inout(int)[] foo(inout(int)[] a, int x, int y) { return a[x .. y]; }

The inout forms a wildcard that stands in for any of mutable, const or immutable. When the function is called, the inout of the return type is changed to whatever the mutable, const, or immutable status of the argument type to the parameter inout was.

Inout types can be implicitly converted to const, but to nothing else. Other types cannot be implicitly converted to inout. Casting to or from inout is not allowed in @safe functions.

If an inout appears in a function parameter list, it must also appear in the return type.

A set of arguments to a function with inout parameters is considered a match if any inout argument types match exactly, or:

  1. No argument types are composed of inout types.
  2. A mutable, const or immutable argument type can be matched against each corresponding parameter inout type.

If such a match occurs, if every match is mutable, then the inout is considered matched with mutable. If every match is immutable, then the inout is considered matched with immutable. Otherwise, the inout is considered matched with const. The inout in the return type is then rewritten to be the inout matched attribute.

Global and static variable types cannot have any inout components.

Note: Shared types are not overlooked. Shared types cannot be matched with inout.

Property Functions

Property functions are tagged with the @property attribute. They can be called without parentheses (hence acting like properties).

struct S {
  int m_x;
  @property {
    int x() { return m_x; }
    int x(int newx) { return m_x = newx; }
  }
}

void foo() {
  S s;
  s.x = 3;   // calls s.x(int)
  bar(s.x);  // calls bar(s.x())
}

Virtual Functions

Virtual functions are functions that are called indirectly through a function pointer table, called a vtbl[], rather than directly. All public and protected member functions which are non-static and aren't templatized are virtual unless the compiler can determine that they will never be overridden (e.g. they're marked with final and don't override any functions in a base class), in which case, it will make them non-virtual. This results in fewer bugs caused by not declaring a function virtual and then overriding it anyway.

Member functions which are private or package are never virtual, and hence cannot be overridden.

Functions with non-D linkage cannot be virtual and hence cannot be overridden.

Member template functions cannot be virtual and hence cannot be overridden.

Functions marked as final may not be overridden in a derived class, unless they are also private. For example:

class A {
  int def() { ... }
  final int foo() { ... }
  final private int bar() { ... }
  private int abc() { ... }
}

class B : A {
  int def() { ... }  // ok, overrides A.def
  int foo() { ... }  // error, A.foo is final
  int bar() { ... }  // ok, A.bar is final private, but not virtual
  int abc() { ... }  // ok, A.abc is not virtual, B.abc is virtual
}

void test(A a) {
  a.def();    // calls B.def
  a.foo();    // calls A.foo
  a.bar();    // calls A.bar
  a.abc();    // calls A.abc
}

void func() {
  B b = new B();
  test(b);
}

Covariant return types are supported, which means that the overriding function in a derived class can return a type that is derived from the type returned by the overridden function:

class A { }
class B : A { }

class Foo {
  A test() { return null; }
}

class Bar : Foo {
  B test() { return null; } // overrides and is covariant with Foo.test()
}

Virtual functions all have a hidden parameter called the this reference, which refers to the class object for which the function is called.

To avoid dynamic binding on member function call, insert base class name before the member function name. For example:

class B {
  int foo() { return 1; }
}
class C : B {
  override int foo() { return 2; }

  void test() {
    assert(B.foo() == 1);  // translated to this.B.foo(), and
                           // calls B.foo statically.
    assert(C.foo() == 2);  // calls C.foo statically, even if
                           // the actual instance of 'this' is D.
  }
}
class D : C {
  override int foo() { return 3; }
}
void main() {
  auto d = new D();
  assert(d.foo() == 3);    // calls D.foo
  assert(d.B.foo() == 1);  // calls B.foo
  assert(d.C.foo() == 2);  // calls C.foo
  d.test();
}

Function Inheritance and Overriding

A functions in a derived class with the same name and parameter types as a function in a base class overrides that function:
class A {
  int foo(int x) { ... }
}

class B : A {
  override int foo(int x) { ... }
}

void test() {
  B b = new B();
  bar(b);
}

void bar(A a) {
  a.foo(1);   // calls B.foo(int)
}

However, when doing overload resolution, the functions in the base class are not considered:

class A {
  int foo(int x) { ... }
  int foo(long y) { ... }
}

class B : A {
  override int foo(long x) { ... }
}

void test() {
  B b = new B();
  b.foo(1);  // calls B.foo(long), since A.foo(int) not considered
  A a = b;
  a.foo(1);    // issues runtime error (instead of calling A.foo(int))
}

To consider the base class's functions in the overload resolution process, use an AliasDeclaration:

class A {
  int foo(int x) { ... }
  int foo(long y) { ... }
}

class B : A {
  alias A.foo foo;
  override int foo(long x) { ... }
}

void test() {
  B b = new B();
  bar(b);
}

void bar(A a) {
  a.foo(1);      // calls A.foo(int)
  B b = new B();
  b.foo(1);      // calls A.foo(int)
}

If such an AliasDeclaration is not used, the derived class's functions completely override all the functions of the same name in the base class, even if the types of the parameters in the base class functions are different. If, through implicit conversions to the base class, those other functions do get called, a core.exception.HiddenFuncError exception is raised:

import core.exception;

class A {
   void set(long i) { }
   void set(int i)  { }
}
class B : A {
   void set(long i) { }
}

void foo(A a) {
  int i;
  try {
    a.set(3);   // error, throws runtime exception since
                // A.set(int) should not be available from B
  }
  catch (HiddenFuncError o) {
     i = 1;
  }
  assert(i == 1);
}

void main() {
  foo(new B);
}

If an HiddenFuncError exception is thrown in your program, the use of overloads and overrides needs to be reexamined in the relevant classes.

The HiddenFuncError exception is not thrown if the hidden function is disjoint, as far as overloading is concerned, from all the other virtual functions is the inheritance hierarchy.

A function parameter's default value is not inherited:

class A {
  void foo(int x = 5) { ... }
}

class B : A {
  void foo(int x = 7) { ... }
}

class C : B {
  void foo(int x) { ... }
}

void test() {
  A a = new A();
  a.foo();       // calls A.foo(5)

  B b = new B();
  b.foo();       // calls B.foo(7)

  C c = new C();
  c.foo();       // error, need an argument for C.foo
}

Inline Functions

There is no inline keyword. The compiler makes the decision whether to inline a function or not, analogously to the register keyword no longer being relevant to a compiler's decisions on enregistering variables. (There is no register keyword either.)

Function Overloading

Functions are overloaded based on how well the arguments to a function can match up with the parameters. The function with the best match is selected. The levels of matching are:

  1. no match
  2. match with implicit conversions
  3. match with conversion to const
  4. exact match

Each argument (including any this pointer) is compared against the function's corresponding parameter, to determine the match level for that argument. The match level for a function is the worst match level of each of its arguments.

Literals do not match ref or out parameters.

If two or more functions have the same match level, then partial ordering is used to try to find the best match. Partial ordering finds the most specialized function. If neither function is more specialized than the other, then it is an ambiguity error. Partial ordering is determined for functions f() and g() by taking the parameter types of f(), constructing a list of arguments by taking the default values of those types, and attempting to match them against g(). If it succeeds, then g() is at least as specialized as f(). For example:

class A { }
class B : A { }
class C : B { }
void foo(A);
void foo(B);

void test() {
  C c;
  /* Both foo(A) and foo(B) match with implicit conversion rules.
   * Applying partial ordering rules,
   * foo(B) cannot be called with an A, and foo(A) can be called
   * with a B. Therefore, foo(B) is more specialized, and is selected.
   */
  foo(c); // calls foo(B)
}

A function with a variadic argument is considered less specialized than a function without.

Functions defined with non-D linkage cannot be overloaded. because the name mangling does not take the parameter types into account.

Overload Sets

Functions declared at the same scope overload against each other, and are called an Overload Set. A typical example of an overload set are functions defined at module level:

module A;
void foo() { }
void foo(long i) { }

A.foo() and A.foo(long) form an overload set. A different module can also define functions with the same name:

module B;
class C { }
void foo(C) { }
void foo(int i) { }

and A and B can be imported by a third module, C. Both overload sets, the A.foo overload set and the B.foo overload set, are found. An instance of foo is selected based on it matching in exactly one overload set:

import A;
import B;

void bar(C c) {
  foo();    // calls A.foo()
  foo(1L);  // calls A.foo(long)
  foo(c);   // calls B.foo(C)
  foo(1,2); // error, does not match any foo
  foo(1);   // error, matches A.foo(long) and B.foo(int)
  A.foo(1); // calls A.foo(long)
}

Even though B.foo(int) is a better match than A.foo(long) for foo(1), it is an error because the two matches are in different overload sets.

Overload sets can be merged with an alias declaration:

import A;
import B;

alias A.foo foo;
alias B.foo foo;

void bar(C c) {
  foo();    // calls A.foo()
  foo(1L);  // calls A.foo(long)
  foo(c);   // calls B.foo(C)
  foo(1,2); // error, does not match any foo
  foo(1);   // calls B.foo(int)
  A.foo(1); // calls A.foo(long)
}

Function Parameters

Parameter storage classes are in, out, ref, lazy, const, immutable, shared, inout or scope. For example:

int foo(in int x, out int y, ref int z, int q);

x is in, y is out, z is ref, and q is none.

  • The function declaration makes it clear what the inputs and outputs to the function are.
  • It eliminates the need for IDL as a separate language.
  • It provides more information to the compiler, enabling more error checking and possibly better code generation.
Parameter Storage Classes
Storage Class | Description
none | parameter becomes a mutable copy of its argument
in | equivalent to const scope
out | parameter is initialized upon function entry with the default value for its type
ref | parameter is passed by reference
scope | references in the parameter cannot be escaped (e.g. assigned to a global variable)
lazy | argument is evaluated by the called function and not by the caller
const | argument is implicitly converted to a const type
immutable | argument is implicitly converted to an immutable type
shared | argument is implicitly converted to a shared type
inout | argument is implicitly converted to an inout type
void foo(out int x) {
  // x is set to int.init,
  // which is 0, at start of foo()
}

int a = 3;
foo(a);
// a is now 0

void abc(out int x) {
  x = 2;
}

int y = 3;
abc(y);
// y is now 2

void def(ref int x) {
  x += 1;
}

int z = 3;
def(z);
// z is now 4

For dynamic array and object parameters, which are passed by reference, in/out/ref apply only to the reference and not the contents.

lazy arguments are evaluated not when the function is called, but when the parameter is evaluated within the function. Hence, a lazy argument can be executed 0 or more times. A lazy parameter cannot be an lvalue.

void dotimes(int n, lazy void exp) {
  while (n--)
    exp();
}

void test() {
  int x;
  dotimes(3, writefln(x++));
}

prints to the console:

0
1
2

A lazy parameter of type void can accept an argument of any type.

Function Default Arguments

Function parameter declarations can have default values:

void foo(int x, int y = 3) {
  ...
}
...
foo(4);   // same as foo(4, 3);

Default parameters are evaluated in the context of the function declaration. If the default value for a parameter is given, all following parameters must also have default values.

Variadic Functions

 Functions taking a variable number of arguments are called variadic functions. A variadic function can take one of three forms:
  1. C-style variadic functions
  2. Variadic functions with type info
  3. Typesafe variadic functions

C-style Variadic Functions

A C-style variadic function is declared as taking a parameter of ... after the required function parameters. It has non-D linkage, such as extern (C):
extern (C) int foo(int x, int y, ...);

foo(3, 4);      // ok
foo(3, 4, 6.8); // ok, one variadic argument
foo(2);         // error, y is a required argument
There must be at least one non-variadic parameter declared.
extern (C) int def(...); // error, must have at least one parameter

C-style variadic functions match the C calling convention for variadic functions, and is most useful for calling C library functions like printf.

Access to variadic arguments is done using the standard library module core.stdc.stdarg.

import core.stdc.stdarg;

void test() {
  foo(3, 4, 5);   // first variadic argument is 5
}

int foo(int x, int y, ...) {

  va_list ap;
  version (X86_64)
    va_start(ap, __va_argsave);
  else version (X86)
    va_start(ap, y);  // y is the last named parameter

  int z;
  va_arg(ap, z);  // z is set to 5

  va_end(ap);
}

D-style Variadic Functions

Variadic functions with argument and type info are declared as taking a parameter of ... after the required function parameters. It has D linkage, and need not have any non-variadic parameters declared:
int abc(char c, ...);   // one required parameter: c
int def(...);           // ok
To access them, the following import is required:
import core.vararg;
These variadic functions have a special local variable declared for them, _argptr, which is a core.vararg reference to the first of the variadic arguments. To access the arguments, _argptr must be used in conjuction with va_arg:
import core.vararg;

void test() {
  foo(3, 4, 5);   // first variadic argument is 5
}

int foo(int x, int y, ...) {

  int z;

  z = va_arg!int(_argptr); // z is set to 5
}
An additional hidden argument with the name _arguments and type TypeInfo[] is passed to the function. _arguments gives the number of arguments and the type of each, enabling the creation of typesafe variadic functions.
import std.stdio;
import core.vararg;

class Foo { int x = 3; }
class Bar { long y = 4; }

void printargs(int x, ...) {
  writefln("%d arguments", _arguments.length);
  for (int i = 0; i < _arguments.length; i++)
  {
    writeln(_arguments[i]);

    if (_arguments[i] == typeid(int))
    {
      int j = va_arg!(int)(_argptr);
      writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(long))
    {
      long j = va_arg!(long)(_argptr);
      writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(double))
    {
      double d = va_arg!(double)(_argptr);
      writefln("\t%g", d);
    }
    else if (_arguments[i] == typeid(Foo))
    {
      Foo f = va_arg!(Foo)(_argptr);
      writefln("\t%s", f);
    }
    else if (_arguments[i] == typeid(Bar))
    {
      Bar b = va_arg!(Bar)(_argptr);
      writefln("\t%s", b);
    }
    else
      assert(0);
  }
}

void main() {
  Foo f = new Foo();
  Bar b = new Bar();

  writefln("%s", f);
  printargs(1, 2, 3L, 4.5, f, b);
}
which prints:
0x00870FE0
5 arguments
int
        2
long
        3
double
        4.5
Foo
        0x00870FE0
Bar
        0x00870FD0

Typesafe Variadic Functions

Typesafe variadic functions are used when the variable argument portion of the arguments are used to construct an array or class object.

For arrays:

int test() {
  return sum(1, 2, 3) + sum(); // returns 6+0
}

int func() {
  int[3] ii = [4, 5, 6];
  return sum(ii);             // returns 15
}

int sum(int[] ar ...) {
  int s;
  foreach (int x; ar)
    s += x;
  return s;
}
For static arrays:
int test() {
  return sum(2, 3);   // error, need 3 values for array
  return sum(1, 2, 3); // returns 6
}

int func() {
  int[3] ii = [4, 5, 6];
  int[] jj = ii;
  return sum(ii); // returns 15
  return sum(jj); // error, type mismatch
}

int sum(int[3] ar ...) {
  int s;
  foreach (int x; ar)
    s += x;
  return s;
}
For class objects:
class Foo {
  int x;
  string s;

  this(int x, string s) {
    this.x = x;
    this.s = s;
  }
}

void test(int x, Foo f ...);

...

Foo g = new Foo(3, "abc");
test(1, g);         // ok, since g is an instance of Foo
test(1, 4, "def");  // ok
test(1, 5);         // error, no matching constructor for Foo
An implementation may construct the object or array instance on the stack. Therefore, it is an error to refer to that instance after the variadic function has returned:
Foo test(Foo f ...) {
  return f;   // error, f instance contents invalid after return
}

int[] test(int[] a ...) {
  return a;       // error, array contents invalid after return
  return a[0..1]; // error, array contents invalid after return
  return a.dup;   // ok, since copy is made
}
For other types, the argument is built with itself, as in:
int test(int i ...) {
  return i;
}

...
test(3);    // returns 3
test(3, 4); // error, too many arguments
int[] x;
test(x);    // error, type mismatch

Lazy Variadic Functions

If the variadic parameter is an array of delegates with no parameters:

void foo(int delegate()[] dgs ...);

Then each of the arguments whose type does not match that of the delegate is converted to a delegate.

int delegate() dg;
foo(1, 3+x, dg, cast(int delegate())null);

is the same as:

foo( { return 1; }, { return 3+x; }, dg, null );

Local Variables

It is an error to use a local variable without first assigning it a value. The implementation may not always be able to detect these cases. Other language compilers sometimes issue a warning for this, but since it is always a bug, it should be an error.

It is an error to declare a local variable that is never referred to. Dead variables, like anachronistic dead code, are just a source of confusion for maintenance programmers.

It is an error to declare a local variable that hides another local variable in the same function:

void func(int x) {
   int x;     // error, hides previous definition of x
   double y;
   ...
   { char y;  // error, hides previous definition of y
     int z;
   }
   { wchar z; // legal, previous z is out of scope
   }
}

While this might look unreasonable, in practice whenever this is done it either is a bug or at least looks like a bug.

It is an error to return the address of or a reference to a local variable.

It is an error to have a local variable and a label with the same name.

Local Static Variables

Local variables in functions can be declared as static or __gshared in which case they are statically allocated rather than being allocated on the stack. As such, their value persists beyond the exit of the function.

void foo() {
  static int n;
  if (++n == 100)
    writeln("called 100 times");
}

The initializer for a static variable must be evaluatable at compile time, and they are initialized upon the start of the thread (or the start of the program for __gshared). There are no static constructors or static destructors for static local variables.

Although static variable name visibility follows the usual scoping rules, the names of them must be unique within a particular function.

void main() {
  { static int x; }
  { static int x; } // error
  { int i; }
  { int i; } // ok
}

Nested Functions

Functions may be nested within other functions:

int bar(int a) {
  int foo(int b) {
    int abc() { return 1; }

    return b + abc();
  }
  return foo(a);
}

void test() {
  int i = bar(3); // i is assigned 4
}

Nested functions can be accessed only if the name is in scope.

void foo()
{
  void A()
  {
    B(); // error, B() is forward referenced
    C(); // error, C undefined
  }
  void B()
  {
    A(); // ok, in scope
    void C()
    {
      void D()
      {
        A();      // ok
        B();      // ok
        C();      // ok
        D();      // ok
      }
    }
  }
  A(); // ok
  B(); // ok
  C(); // error, C undefined
}

and:

int bar(int a) {
  int foo(int b) { return b + 1; }
  int abc(int b) { return foo(b); }   // ok
  return foo(a);
}

void test() {
  int i = bar(3);     // ok
  int j = bar.foo(3); // error, bar.foo not visible
}

Nested functions have access to the variables and other symbols defined by the lexically enclosing function. This access includes both the ability to read and write them.

int bar(int a) {
  int c = 3;

  int foo(int b) {
    b += c;       // 4 is added to b
    c++;          // bar.c is now 5
    return b + c; // 12 is returned
  }
  c = 4;
  int i = foo(a); // i is set to 12
  return i + c;   // returns 17
}

void test() {
  int i = bar(3); // i is assigned 17
}

This access can span multiple nesting levels:

int bar(int a) {
  int c = 3;

  int foo(int b) {
      int abc() {
          return c;   // access bar.c
      }
      return b + c + abc();
  }
  return foo(3);
}

Static nested functions cannot access any stack variables of any lexically enclosing function, but can access static variables. This is analogous to how static member functions behave.

int bar(int a) {
  int c;
  static int d;

  static int foo(int b) {
    b = d;          // ok
    b = c;          // error, foo() cannot access frame of bar()
    return b + 1;
  }
  return foo(a);
}

Functions can be nested within member functions:

struct Foo {
  int a;

  int bar() {
    int c;

    int foo() {
      return c + a;
    }
    return 0;
  }
}

Nested functions always have the D function linkage type.

Unlike module level declarations, declarations within function scope are processed in order. This means that two nested functions cannot mutually call each other:

void test() {
  void foo() { bar(); } // error, bar not defined
  void bar() { foo(); } // ok
}

One solution is declare both functions as members of a nested struct. Another solution is to use a delegate:

void test() {
  void delegate() fp;
  void foo() { fp(); }
  void bar() { foo(); }
  fp = &bar;
}

Nested functions cannot be overloaded.

Delegates, Function Pointers, and Closures

A function pointer can point to a static nested function:

int function() fp;

void test() {
  static int a = 7;
  static int foo() { return a + 3; }

  fp = &foo;
}

void bar() {
  test();
  int i = fp();       // i is set to 10
}

A delegate can be set to a non-static nested function:

int delegate() dg;

void test() {
  int a = 7;
  int foo() { return a + 3; }

  dg = &foo;
  int i = dg(); // i is set to 10
}

The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error.

int* bar() {
  int b;
  test();
  int i = dg(); // ok, test.a is in a closure and still exists
  return &b;    // error, bar.b not valid after bar() exits
}

Delegates to non-static nested functions contain two pieces of data: the pointer to the stack frame of the lexically enclosing function (called the frame pointer) and the address of the function. This is analogous to struct/class non-static member function delegates consisting of a this pointer and the address of the member function. Both forms of delegates are interchangeable, and are actually the same type:

struct Foo {
  int a = 7;
  int bar() { return a; }
}

int foo(int delegate() dg) {
  return dg() + 1;
}

void test() {
  int x = 27;
  int abc() { return x; }
  Foo f;
  int i;

  i = foo(&abc);   // i is set to 28
  i = foo(&f.bar); // i is set to 8
}

This combining of the environment and the function is called a dynamic closure.

The .ptr property of a delegate will return the frame pointer value as a void*.

The .funcptr property of a delegate will return the function pointer value as a function type.

Future directions: Function pointers and delegates may merge into a common syntax and be interchangeable with each other.

Anonymous Functions and Anonymous Delegates

See FunctionLiterals.

main() Function

For console programs, main() serves as the entry point. It gets called after all the module initializers are run, and after any unittests are run. After it returns, all the module destructors are run. main() must be declared using one of the following forms:

void main() { ... }
void main(string[] args) { ... }
int main() { ... }
int main(string[] args) { ... }

Compile Time Function Execution (CTFE)

Functions which are both portable and free of side-effects can be executed at compile time. This is useful when constant folding algorithms need to include recursion and looping. Compile time function execution is subject to the following restrictions:

  1. The function source code must be available to the compiler. Functions which exist in the source code only as extern declarations cannot be executed at compile time.
  2. Executed expressions may not reference any global or local static variables.
  3. asm statements are not permitted
  4. Non-portable casts (eg, from int[] to float[]), including casts which depend on endianness, are not permitted. Casts between signed and unsigned types are permitted

Pointers are permitted in CTFE, provided they are used safely:

  • C-style semantics on pointer arithmetic are strictly enforced. Pointer arithmetic is permitted only on pointers which point to static or dynamic array elements. Such pointers must point to an element of the array, or to the first element past the array. Pointer arithmetic is completely forbidden on pointers which are null, or which point to a non-array.
  • The memory location of different memory blocks is not defined. Ordered comparison (<, <=, >, >=) between two pointers is permitted when both pointers point to the same array, or when at least one pointer is null.
  • Pointer comparisons between independent memory blocks will generate a compile-time error, unless two such comparisons are combined using && or || to yield a result which is independent of the ordering of memory blocks. Each comparison must consist of two pointer expressions compared with <, <=, >, or >=, and may optionally be negated with ! .

    For example, the expression (p1 > q1 && p2 <= q2) is permitted when p1, p2 are expressions yielding pointers to memory block P, and q1, q2 are expressions yielding pointers to memory block Q, even when P and Q are unrelated memory blocks. It returns true if [p1..p2] lies inside [q1..q2], and false otherwise. Similarly, the expression (p1 < q1 || p2 > q2) is true if [p1..p2] lies outside [q1..q2], and false otherwise.

  • Equality comparisons (==, !=, is, !is) are permitted between all pointers, without restriction.
  • Any pointer may be cast to void * and from void * back to its original type. Casting between pointer and non-pointer types is prohibited.

Note that the above restrictions apply only to expressions which are actually executed. For example:

static int y = 0;

int countTen(int x) {
  if (x > 10)
    ++y;
  return x;
}

static assert(countTen(6) == 6); // OK
static assert(countTen(12) == 12);  // invalid, modifies y.

The __ctfe boolean pseudo-variable, which evaluates to true at compile time, but false at run time, can be used to provide an alternative execution path to avoid operations which are forbidden at compile time. Every usage of __ctfe is evaluated before code generation and therefore has no run-time cost, even if no optimizer is used.

In order to be executed at compile time, the function must appear in a context where it must be so executed, for example:

  • initialization of a static variable
  • dimension of a static array
  • argument for a template value parameter
template eval( A... ) {
  const typeof(A[0]) eval = A[0];
}

int square(int i) {
  return i * i;
}

void foo() {
  static j = square(3);     // compile time
  writefln(j);
  writefln(square(4));      // run time
  writefln(eval!(square(5))); // compile time
}

Executing functions at compile time can take considerably longer than executing it at run time. If the function goes into an infinite loop, it will hang at compile time (rather than hanging at run time).

Non-recoverable errors (such as assert failures) do not throw exceptions; instead, they end interpretation immediately.

Functions executed at compile time can give different results from run time in the following scenarios:

  • floating point computations may be done at a higher precision than run time
  • dependency on implementation defined order of evaluation
  • use of uninitialized variables

These are the same kinds of scenarios where different optimization settings affect the results.

String Mixins and Compile Time Function Execution

Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. This means that the semantics of a function cannot depend on compile time values of the function. For example:

int foo(char[] s) {
  return mixin(s);
}

const int x = foo("1");

is illegal, because the runtime code for foo() cannot be generated. A function template would be the appropriate method to implement this sort of thing.

Function Safety

Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior. Undefined behavior is often used as a vector for malicious attacks.

Safe Functions

Safe functions are marked with the @safe attribute.

The following operations are not allowed in safe functions:

  • No casting from a pointer type to any type other than void*.
  • No casting from any non-pointer type to a pointer type.
  • No modification of pointer values.
  • Cannot access unions that have pointers or references overlapping with other types.
  • Calling any system functions.
  • No catching of exceptions that are not derived from class Exception.
  • No inline assembler.
  • No explicit casting of mutable objects to immutable.
  • No explicit casting of immutable objects to mutable.
  • No explicit casting of thread local objects to shared.
  • No explicit casting of shared objects to thread local.
  • No taking the address of a local variable or function parameter.
  • Cannot access __gshared variables.

Functions nested inside safe functions default to being safe functions.

Safe functions are covariant with trusted or system functions.

Note: The verifiable safety of functions may be compromised by bugs in the compiler and specification. Please report all such errors so they can be corrected.

Trusted Functions

Trusted functions are marked with the @trusted attribute.

Trusted functions are guaranteed by the programmer to not exhibit any undefined behavior if called by a safe function. Generally, trusted functions should be kept small so that they are easier to manually verify.

Trusted functions may call safe, trusted, or system functions.

Trusted functions are covariant with safe or system functions.

System Functions

System functions are functions not marked with @safe or @trusted and are not nested inside @safe functions. System functions may be marked with the @system attribute. A function being system does not mean it actually is unsafe, it just means that the compiler is unable to verify that it cannot exhibit undefined behavior.

System functions are not covariant with trusted or safe functions.

Function Attribute Inference

FunctionLiterals and function templates, since their function bodies are always present, infer the pure, nothrow, and @safe attributes unless specifically overridden.

Attribute inference is not done for other functions, even if the function body is present.

The inference is done by determining if the function body follows the rules of the particular attribute.

Cyclic functions (i.e. functions that wind up directly or indirectly calling themselves) are inferred as being impure, throwing, and @system.

If a function attempts to test itself for those attributes, then the function is inferred as not having those attributes.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Operator Overloading - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Operator Overloading

Operator overloading is accomplished by rewriting operators whose operands are class or struct objects into calls to specially named member functions. No additional syntax is used.

  • Unary Operator Overloading
  • Cast Operator Overloading
  • Binary Operator Overloading
  • Overloading == and !=
  • Overloading < <=, > and >=
  • Function Call Operator Overloading
  • Assignment Operator Overloading
  • Op Assignment Operator Overloading
  • Index Operator Overloading
  • Slice Operator Overloading
  • Forwarding

Unary Operator Overloading

Overloadable Unary Operators
op | rewrite
-e | e.opUnary!("-")()
+e | e.opUnary!("+")()
~e | e.opUnary!("~")()
*e | e.opUnary!("*")()
++e | e.opUnary!("++")()
--e | e.opUnary!("--")()

For example, in order to overload the - (negation) operator for struct S, and no other operator:

struct S {
  int m;

  int opUnary(string s)() if (s == "-") {
    return -m;
  }
}

int foo(S s) {
  return -s;
}

Postincrement e++ and Postdecrement e-- Operators

These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators:

Postfix Operator Rewrites
op | rewrite
e-- | (auto t = e, --e, t)
e++ | (auto t = e, ++e, t)

Overloading Index Unary Operators

Overloadable Index Unary Operators
op | rewrite
-a[b1, b2, ... bn] | a.opIndexUnary!("-")(b1, b2, ... bn)
+a[b1, b2, ... bn] | a.opIndexUnary!("+")(b1, b2, ... bn)
~a[b1, b2, ... bn] | a.opIndexUnary!("~")(b1, b2, ... bn)
*a[b1, b2, ... bn] | a.opIndexUnary!("*")(b1, b2, ... bn)
++a[b1, b2, ... bn] | a.opIndexUnary!("++")(b1, b2, ... bn)
--a[b1, b2, ... bn] | a.opIndexUnary!("--")(b1, b2, ... bn)

Overloading Slice Unary Operators

Overloadable Slice Unary Operators
op | rewrite
-a[i..j] | a.opSliceUnary!("-")(i, j)
+a[i..j] | a.opSliceUnary!("+")(i, j)
~a[i..j] | a.opSliceUnary!("~")(i, j)
*a[i..j] | a.opSliceUnary!("*")(i, j)
++a[i..j] | a.opSliceUnary!("++")(i, j)
--a[i..j] | a.opSliceUnary!("--")(i, j)
-a[ ] | a.opSliceUnary!("-")()
+a[ ] | a.opSliceUnary!("+")()
~a[ ] | a.opSliceUnary!("~")()
*a[ ] | a.opSliceUnary!("*")()
++a[ ] | a.opSliceUnary!("++")()
--a[ ] | a.opSliceUnary!("--")()

Cast Operator Overloading

Cast Operators
op | rewrite
cast(type)e | e.opCast!(type)()

Boolean Operations

Notably absent from the list of overloaded unary operators is the ! logical negation operator. More obscurely absent is a unary operator to convert to a bool result. Instead, these are covered by a rewrite to:

opCast!(bool)(e)

So,

if (e)   =>  if (e.opCast!(bool))
if (!e)  =>  if (!e.opCast!(bool))

etc., whenever a bool result is expected. This only happens, however, for instances of structs. Class references are converted to bool by checking to see if the class reference is null or not.

Binary Operator Overloading

The following binary operators are overloadable:

Overloadable Binary Operators
+ | - | * | / | % | ^^ | &
| | ^ | << | >> | >>> | ~ | in

The expression:

a op b

is rewritten as both:

a.opBinary!("op")(b)
b.opBinaryRight!("op")(a)

and the one with the ‘better’ match is selected. It is an error for both to equally match.

Operator overloading for a number of operators can be done at the same time. For example, if only the + or - operators are supported:

T opBinary(string op)(T rhs) {
   static if (op == "+") return data + rhs.data;
   else static if (op == "-") return data - rhs.data;
   else static assert(0, "Operator "~op~" not implemented");
}

To do them all en masse:

T opBinary(string op)(T rhs) {
     return mixin("data "~op~" rhs.data");
}

Overloading == and !=

Expressions of the form a != b are rewritten as !(a == b).

Given a == b :

  1. If a and b are both class objects, then the expression is rewritten as:
    .object.opEquals(a, b)

    and that function is implemented as:

    bool opEquals(Object a, Object b) {
  if (a is b) return true;
  if (a is null || b is null) return false;
  if (typeid(a) == typeid(b)) return a.opEquals(b);
  return a.opEquals(b) && b.opEquals(a);
}
  2. Otherwise the expressions a.opEquals(b) and b.opEquals(a) are tried. If both resolve to the same opEquals function, then the expression is rewritten to be a.opEquals(b).
  3. If one is a better match then the other, or one compiles and the other does not, the one is selected.
  4. Otherwise, an error results.

If overridding Object.opEquals() for classes, the class member function signature should look like:

class C {
  override bool opEquals(Object o) { ... }
}

If structs declare an opEquals member function, it should follow the following form:

struct S {
  bool opEquals(ref const S s) { ... }  // for l-values (e.g. variables)
  bool opEquals(const S s) { ... }      // for r-values (e.g. temporaries)
}

Alternatively you can declare a single templated opEquals function with an auto ref parameter:

struct S {
  bool opEquals()(auto ref S s) { ... }  // for l-values and r-values
}

Overloading < <=, > and >=

Comparison operations are rewritten as follows:

Overloadable Unary Operators
comparison | rewrite 1 | rewrite 2
a < b | a.opCmp(b) < 0 | b.opCmp(a) > 0
a <= b | a.opCmp(b) <= 0 | b.opCmp(a) >= 0
a > b | a.opCmp(b) > 0 | b.opCmp(a) < 0
a >= b | a.opCmp(b) >= 0 | b.opCmp(a) <= 0

Both rewrites are tried. If only one compiles, that one is taken. If they both resolve to the same function, the first rewrite is done. If they resolve to different functions, the best matching one is used. If they both match the same, but are different functions, an ambiguity error results.

If overriding Object.opCmp() for classes, the class member function signature should look like:

class C {
  override int opCmp(Object o) { ... }
}

If structs declare an opCmp member function, it should follow the following form:

struct S {
  int opCmp(ref const S s) const { ... }
}

Function Call Operator Overloading f()

The function call operator, (), can be overloaded by declaring a function named opCall:

struct F {
  int opCall();
  int opCall(int x, int y, int z);
}

void test() {
  F f;
  int i;

  i = f();      // same as i = f.opCall();
  i = f(3,4,5); // same as i = f.opCall(3,4,5);
}

In this way a struct or class object can behave as if it were a function.

Assignment Operator Overloading

The assignment operator = can be overloaded if the lvalue is a struct aggregate, and opAssign is a member function of that aggregate.

The assignment operator cannot be overloaded for rvalues that can be implicitly cast to the lvalue type. Furthermore, the following parameter signatures for opAssign are not allowed:

opAssign(...)
opAssign(T)
opAssign(T, ...)
opAssign(T ...)
opAssign(T, U = defaultValue, etc.)

where T is the same type as the aggregate type A, is implicitly convertible to A, or if A is a struct and T is a pointer to a type that is implicitly convertible to A.

Index Assignment Operator Overloading

If the left hand side of an assignment is an index operation on a struct or class instance, it can be overloaded by providing an opIndexAssign member function. Expressions of the form a[b1, b2, ... bn] = c are rewritten as a.opIndexAssign(c, b1, b2, ... bn).

struct A {
  int opIndexAssign(int value, size_t i1, size_t i2);
}

void test() {
  A a;

  a[i,3] = 7;  // same as a.opIndexAssign(7,i,3);
}

Slice Assignment Operator Overloading

If the left hand side of an assignment is a slice operation on a struct or class instance, it can be overloaded by providing an opSliceAssign member function. Expressions of the form a[i..j] = c are rewritten as a.opSliceAssign(c, i, j), and a[] = c as a.opSliceAssign(c).

struct A {
  int opSliceAssign(int v);  // overloads a[] = v
  int opSliceAssign(int v, size_t x, size_t y);  // overloads a[i .. j] = v
}

void test() {
  A a;
  int v;

  a[] = v;  // same as a.opSliceAssign(v);
  a[3..4] = v;  // same as a.opSliceAssign(v,3,4);
}

Op Assignment Operator Overloading

The following op assignment operators are overloadable:

Overloadable Op Assignment Operators
+= | -= | *= | /= | %= | ^^= | &=
|= | ^= | <<= | >>= | >>>= | ~= |

The expression:

a op= b

is rewritten as:

a.opOpAssign!("op")(b)

Index Op Assignment Operator Overloading

If the left hand side of an op= is an index expression on a struct or class instance and opIndexOpAssign is a member:

a[b1, b2, ... bn] op= c

it is rewritten as:

a.opIndexOpAssign!("op")(c, b1, b2, ... bn)

Slice Op Assignment Operator Overloading

If the left hand side of an op= is a slice expression on a struct or class instance and opSliceOpAssign is a member:

a[i..j] op= c

it is rewritten as:

a.opSliceOpAssign!("op")(c, i, j)

and

a[] op= c

it is rewritten as:

a.opSliceOpAssign!("op")(c)

Index Operator Overloading

The array index operator, a[b1, b2, ... bn], can be overloaded by declaring a function named opIndex with one or more parameters.

struct A {
  int opIndex(size_t i1, size_t i2, size_t i3);
}

void test() {
  A a;
  int i;

  i = a[5,6,7];  // same as i = a.opIndex(5,6,7);
}

In this way a struct or class object can behave as if it were an array.

If an index expression can be rewritten using opIndexAssign or opIndexOpAssign, those are preferred over opIndex.

Slice Operator Overloading

Overloading the slicing operator means overloading expressions like a[] and a[i..j]. This can be done by declaring a member function named opSlice.

class A {
  int opSlice();  // overloads a[]
  int opSlice(size_t x, size_t y); // overloads a[i .. j]
}

void test() {
  A a = new A();
  int i;
  int v;

  i = a[];         // same as i = a.opSlice();
  i = a[3..4];  // same as i = a.opSlice(3,4);
}

If a slice expression can be rewritten using opSliceAssign or opSliceOpAssign, those are preferred over opSlice.

Forwarding

Member names not found in a class or struct can be forwarded to a template function named opDispatch for resolution.

import std.stdio;

struct S {
  void opDispatch(string s, T)(T i)
  {
    writefln("S.opDispatch('%s', %s)", s, i);
  }
}

class C {
  void opDispatch(string s)(int i) {
    writefln("C.opDispatch('%s', %s)", s, i);
  }
}

struct D {
  template opDispatch(string s) {
    enum int opDispatch = 8;
  }
}

void main() {
  S s;
  s.opDispatch!("hello")(7);
  s.foo(7);

  auto c = new C();
  c.foo(8);

  D d;
  writefln("d.foo = %s", d.foo);
  assert(d.foo == 8);
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Templates - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Templates

I think that I can safely say that nobody understands template mechanics. -- Richard Deyman

Templates are D's approach to generic programming. Templates are defined with a TemplateDeclaration:

TemplateDeclaration:
    template TemplateIdentifier ( TemplateParameterList ) Constraintopt
        { DeclDefs }

TemplateIdentifier:
    Identifier

TemplateParameterList:
    TemplateParameter
    TemplateParameter ,
    TemplateParameter , TemplateParameterList

TemplateParameter:
    TemplateTypeParameter
    TemplateValueParameter
    TemplateAliasParameter
    TemplateTupleParameter
    TemplateThisParameter

The body of the TemplateDeclaration must be syntactically correct even if never instantiated. Semantic analysis is not done until instantiated. A template forms its own scope, and the template body can contain classes, structs, types, enums, variables, functions, and other templates.

Template parameters can be types, values, symbols, or tuples. Types can be any type. Value parameters must be of an integral type, floating point type, or string type and specializations for them must resolve to an integral constant, floating point constant, null, or a string literal. Symbols can be any non-local symbol. Tuples are a sequence of 0 or more types, values or symbols.

Template parameter specializations constrain the values or types the TemplateParameter can accept.

Template parameter defaults are the value or type to use for the TemplateParameter in case one is not supplied.

Explicit Template Instantiation

Templates are explicitly instantiated with:

TemplateInstance:
    TemplateIdentifier !( TemplateArgumentList )
    TemplateIdentifier ! TemplateSingleArgument

TemplateArgumentList:
    TemplateArgument
    TemplateArgument ,
    TemplateArgument , TemplateArgumentList

TemplateArgument:
    Type
    AssignExpression
    Symbol

Symbol:
    SymbolTail
    . SymbolTail

SymbolTail:
    Identifier
    Identifier . SymbolTail
    TemplateInstance
    TemplateInstance . SymbolTail

TemplateSingleArgument:
    Identifier
    BasicTypeX
    CharacterLiteral
    StringLiteral
    IntegerLiteral
    FloatLiteral
    true
    false
    null
    __FILE__
    __LINE__

Once instantiated, the declarations inside the template, called the template members, are in the scope of the TemplateInstance:

template TFoo(T) { alias T* t; }
...
TFoo!(int).t x; // declare x to be of type int*

If the TemplateArgument is one token long, the parentheses can be omitted:

TFoo!int.t x;   // same as TFoo!(int).t x;

A template instantiation can be aliased:

template TFoo(T) { alias T* t; }
alias TFoo!(int) abc;
abc.t x;        // declare x to be of type int*

Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example:

template TFoo(T) { T f; }
alias TFoo!(int) a;
alias TFoo!(int) b;
...
a.f = 3;
assert(b.f == 3);  // a and b refer to the same instance of TFoo

This is true even if the TemplateInstances are done in different modules.

Even if template arguments are implicitly converted to the same template parameter type, they still refer to different instances:

struct TFoo(int x) { }
static assert(is(TFoo!(3) == TFoo!(2 + 1))); // 3 and 2+1 are both 3 of type int
static assert(!is(TFoo!(3) == TFoo!(3u)));   // 3u and 3 are different types

If multiple templates with the same TemplateIdentifier are declared, they are distinct if they have a different number of arguments or are differently specialized.

For example, a simple generic copy template would be:

template TCopy(T) {
  void copy(out T to, T from) {
    to = from;
  }
}

To use the template, it must first be instantiated with a specific type:

int i;
TCopy!(int).copy(i, 3);

Instantiation Scope

TemplateInstantances are always performed in the scope of where the TemplateDeclaration is declared, with the addition of the template parameters being declared as aliases for their deduced types.

For example:

module a
template TFoo(T) { void bar() { func(); } }
module b
import a;

void func() { }
alias TFoo!(int) f; // error: func not defined in module a

and:

module a
template TFoo(T) { void bar() { func(1); } }
void func(double d) { }
module b
import a;

void func(int i) { }
alias TFoo!(int) f;
...
f.bar();  // will call a.func(double)

TemplateParameter specializations and default values are evaluated in the scope of the TemplateDeclaration.

Argument Deduction

The types of template parameters are deduced for a particular template instantiation by comparing the template argument with the corresponding template parameter.

For each template parameter, the following rules are applied in order until a type is deduced for each parameter:

  1. If there is no type specialization for the parameter, the type of the parameter is set to the template argument.
  2. If the type specialization is dependent on a type parameter, the type of that parameter is set to be the corresponding part of the type argument.
  3. If after all the type arguments are examined there are any type parameters left with no type assigned, they are assigned types corresponding to the template argument in the same position in the TemplateArgumentList.
  4. If applying the above rules does not result in exactly one type for each template parameter, then it is an error.

For example:

template TFoo(T) { }
alias TFoo!(int) Foo1;     // (1) T is deduced to be int
alias TFoo!(char*) Foo2;   // (1) T is deduced to be char*

template TBar(T : T*) { }
alias TBar!(char*) Foo3;   // (2) T is deduced to be char

template TAbc(D, U : D[]) { }
alias TAbc!(int, int[]) Bar1;  // (2) D is deduced to be int, U is int[]
alias TAbc!(char, int[]) Bar2; // (4) error, D is both char and int

template TDef(D : E*, E) { }
alias TDef!(int*, int) Bar3; // (1) E is int
                             // (3) D is int*

Deduction from a specialization can provide values for more than one parameter:

template Foo(T: T[U], U) {
  ...
}

Foo!(int[long])  // instantiates Foo with T set to int, U set to long

When considering matches, a class is considered to be a match for any super classes or interfaces:

class A { }
class B : A { }

template TFoo(T : A) { }
alias TFoo!(B) Foo4;    // (3) T is B

template TBar(T : U*, U : A) { }
alias TBar!(B*, B) Foo5; // (2) T is B*
                         // (3) U is B

Template Type Parameters

TemplateTypeParameter:
    Identifier
    Identifier TemplateTypeParameterSpecialization
    Identifier TemplateTypeParameterDefault
    Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault

TemplateTypeParameterSpecialization:
     : Type

TemplateTypeParameterDefault:
     = Type

Specialization

Templates may be specialized for particular types of arguments by following the template parameter identifier with a : and the specialized type. For example:

template TFoo(T)        { ... } // #1
template TFoo(T : T[])  { ... } // #2
template TFoo(T : char) { ... } // #3
template TFoo(T,U,V)    { ... } // #4

alias TFoo!(int) foo1;         // instantiates #1
alias TFoo!(double[]) foo2;    // instantiates #2 with T being double
alias TFoo!(char) foo3;        // instantiates #3
alias TFoo!(char, int) fooe;   // error, number of arguments mismatch
alias TFoo!(char, int, int) foo4; // instantiates #4

The template picked to instantiate is the one that is most specialized that fits the types of the TemplateArgumentList. Determine which is more specialized is done the same way as the C++ partial ordering rules. If the result is ambiguous, it is an error.

Template This Parameters

TemplateThisParameter:
    this TemplateTypeParameter

TemplateThisParameters are used in member function templates to pick up the type of the this reference.

import std.stdio;

struct S {
  const void foo(this T)(int i) {
    writeln(typeid(T));
  }
}

void main() {
  const(S) s;
  (&s).foo(1);
  S s2;
  s2.foo(2);
  immutable(S) s3;
  s3.foo(3);
}

Prints:

const(S)
S
immutable(S)

Template Value Parameters

TemplateValueParameter:
    BasicType Declarator
    BasicType Declarator TemplateValueParameterSpecialization
    BasicType Declarator TemplateValueParameterDefault
    BasicType Declarator TemplateValueParameterSpecialization TemplateValueParameterDefault

TemplateValueParameterSpecialization:
    : ConditionalExpression

TemplateValueParameterDefault:
   = __FILE__
    = __LINE__
    = AssignExpression

The __FILE__ and __LINE__ expand to the source file name and line number at the point of instantiation.

Template value parameter types can be any type which can be statically initialized at compile time. Template value arguments can be integer values, floating point values, nulls, string values, array literals of template value arguments, associative array literals of template value arguments, or struct literals of template value arguments.

template foo(string s) {
  string bar() { return s ~ " betty"; }
}

void main() {
  writefln("%s", foo!("hello").bar()); // prints: hello betty
}

This example of template foo has a value parameter that is specialized for 10:

template foo(U : int, int T : 10) {
  U x = T;
}

void main() {
  assert(foo!(int, 10).x == 10);
}

Template Alias Parameters

TemplateAliasParameter:
    alias Identifier TemplateAliasParameterSpecializationopt TemplateAliasParameterDefaultopt
    alias BasicType Declarator TemplateAliasParameterSpecializationopt TemplateAliasParameterDefaultopt

TemplateAliasParameterSpecialization:
    : Type
    : ConditionalExpression

TemplateAliasParameterDefault:
    = Type
    = ConditionalExpression

Alias parameters enable templates to be parameterized with any type of D symbol, including global names, local names, typedef names, module names, template names, and template instance names. Literals can also be used as arguments to alias parameters.

  • Global names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

void test() {
  alias Foo!(x) bar;
  *bar.p = 3;       // set x to 3
  static int y;
  alias Foo!(y) abc;
  *abc.p = 3;       // set y to 3
}
  • Type names
    class Foo {
  static int p;
}

template Bar(alias T) {
  alias T.p q;
}

void test() {
  alias Bar!(Foo) bar;
  bar.q = 3;  // sets Foo.p to 3
}
  • Module names
    import std.string;

template Foo(alias X) {
  alias X.toString y;
}

void test() {
  alias Foo!(std.string) bar;
  bar.y(3);   // calls std.string.toString(3)
}
  • Template names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

template Bar(alias T) {
  alias T!(x) abc;
}

void test() {
  alias Bar!(Foo) bar;
  *bar.abc.p = 3;  // sets x to 3
}
  • Template alias names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

template Bar(alias T) {
  alias T.p q;
}

void test() {
  alias Foo!(x) foo;
  alias Bar!(foo) bar;
  *bar.q = 3;  // sets x to 3
}
  • Literals

template Foo(alias X, alias Y) {
  static int i = X;
  static string s = Y;
}

void test() {
  alias Foo!(3, "bar") foo;
  writeln(foo.i, foo.s);  // prints 3bar
}

Template Tuple Parameters

TemplateTupleParameter:
        Identifier ...

If the last template parameter in the TemplateParameterList is declared as a TemplateTupleParameter, it is a match with any trailing template arguments. The sequence of arguments form a Tuple. A Tuple is not a type, an expression, or a symbol. It is a sequence of any mix of types, expressions or symbols.

A Tuple whose elements consist entirely of types is called a TypeTuple. A Tuple whose elements consist entirely of expressions is called an ExpressionTuple.

A Tuple can be used as an argument list to instantiate another template, or as the list of parameters for a function.

template Print(A ...) {
  void print() {
    writefln("args are ", A);
  }
}

template Write(A ...) {
  void write(A a) // A is a TypeTuple
                  // a is an ExpressionTuple
  {
    writefln("args are ", a);
  }
}

void main() {
  Print!(1,'a',6.8).print();                    // prints: args are 1a6.8
  Write!(int, char, double).write(1, 'a', 6.8); // prints: args are 1a6.8
}

Template tuples can be deduced from the types of the trailing parameters of an implicitly instantiated function template:

template Foo(T, R...) {
  void Foo(T t, R r) {
    writefln(t);
    static if (r.length) // if more arguments
      Foo(r);            // do the rest of the arguments
  }
}

void main() {
  Foo(1, 'a', 6.8);
}

prints:

1
a
6.8

The tuple can also be deduced from the type of a delegate or function parameter list passed as a function argument:

import std.stdio;

/* R is return type
 * A is first argument type
 * U is TypeTuple of rest of argument types
 */
R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg)
{
  struct Foo
  {
    typeof(dg) dg_m;
    typeof(arg) arg_m;

    R bar(U u)
    {
      return dg_m(arg_m, u);
    }
  }

  Foo* f = new Foo;
  f.dg_m = dg;
  f.arg_m = arg;
  return &f.bar;
}

void main()
{
  int plus(int x, int y, int z)
  {
    return x + y + z;
  }

  auto plus_two = Curry(&plus, 2);
  writefln("%d", plus_two(6, 8)); // prints 16
}

The number of elements in a Tuple can be retrieved with the .length property. The nth element can be retrieved by indexing the Tuple with [n], and sub tuples can be created with the slicing syntax.

Tuples are static compile time entities, there is no way to dynamically change, add, or remove elements.

If both a template with a tuple parameter and a template without a tuple parameter exactly match a template instantiation, the template without a TemplateTupleParameter is selected.

Template Parameter Default Values

Trailing template parameters can be given default values:

template Foo(T, U = int) { ... }
Foo!(uint,long); // instantiate Foo with T as uint, and U as long
Foo!(uint);      // instantiate Foo with T as uint, and U as int

template Foo(T, U = T*) { ... }
Foo!(uint);      // instantiate Foo with T as uint, and U as uint*

Implicit Template Properties

If a template has exactly one member in it, and the name of that member is the same as the template name, that member is assumed to be referred to in a template instantiation:

template Foo(T) {
  T Foo; // declare variable Foo of type T
}

void test() {
  Foo!(int) = 6; // instead of Foo!(int).Foo
}

Template Constructors

TemplatedConstructor:
    this ( TemplateParameterList ) Parameters Constraintopt FunctionBody

Templates can be used to form constructors for classes and structs.

Class Templates

ClassTemplateDeclaration:
    class Identifier ( TemplateParameterList ) Constraintopt BaseClassListopt ClassBody

If a template declares exactly one member, and that member is a class with the same name as the template:

template Bar(T) {
  class Bar {
    T member;
  }
}

then the semantic equivalent, called a ClassTemplateDeclaration can be written as:

class Bar(T) {
  T member;
}

Struct, Union, and Interface Templates

StructTemplateDeclaration:
    struct Identifier ( TemplateParameterList ) Constraintopt StructBody

UnionTemplateDeclaration:
    union Identifier ( TemplateParameterList ) Constraintopt StructBody

InterfaceTemplateDeclaration:
    interface Identifier ( TemplateParameterList ) Constraintopt BaseInterfaceListopt InterfaceBody

Analogously to class templates, struct, union and interfaces can be transformed into templates by supplying a template parameter list.

Function Templates

If a template declares exactly one member, and that member is a function with the same name as the template, it is a function template declaration. Alternatively, a function template declaration is a function declaration with a TemplateParameterList immediately preceding the Parameters.

A function template to compute the square of type T is:

T Square(T)(T t) {
  return t * t;
}

Function templates can be explicitly instantiated with a !(TemplateArgumentList):

writefln("The square of %s is %s", 3, Square!(int)(3));

or implicitly, where the TemplateArgumentList is deduced from the types of the function arguments:

writefln("The square of %s is %s", 3, Square(3));  // T is deduced to be int

If there are fewer arguments supplied in the TemplateArgumentList than parameters in the TemplateParameterList, the arguments fulfill parameters from left to right, and the rest of the parameters are then deduced from the function arguments.

Function template type parameters that are to be implicitly deduced may not have specializations:

void Foo(T : T*)(T t) { ... }

int x,y;
Foo!(int*)(x);   // ok, T is not deduced from function argument
Foo(&y);         // error, T has specialization

Template arguments not implicitly deduced can have default values:

void Foo(T, U=T*)(T t) { U p; ... }

int x;
Foo(&x);    // T is int, U is int*

Function templates can have their return types deduced based on the first ReturnStatement in the function:

auto Square(T)(T t) {
  return t * t;
}

If there is more than one return statement, then the types of the return statement expressions must match. If there are no return statements, then the return type of the function template is void.

Function Templates with Auto Ref Parameters

An auto ref function template parameter becomes a ref parameter if its corresponding argument is an lvalue, otherwise it becomes a value parameter:

int foo(T...)(auto ref T x) {
  int result;

  foreach (i, v; x)
  {
    if (v == 10)
      assert(__traits(isRef, x[i]));
    else
      assert(!__traits(isRef, x[i]));
    result += v;
  }
  return result;
}

void main() {
  int y = 10;
  int r;
  r = foo(8);       // returns 8
  r = foo(y);       // returns 10
  r = foo(3, 4, y); // returns 17
  r = foo(4, 5, y); // returns 19
  r = foo(y, 6, y); // returns 26
}

Auto ref parameters can be combined with auto ref return attributes:

auto ref min(T, U)(auto ref T lhs, auto ref U rhs)
{
  return lhs > rhs ? rhs : lhs;
}

void main()
{
  int x = 7, y = 8;
  int i;

  i = min(4, 3);     // returns 3
  i = min(x, y);     // returns 7
  min(x, y) = 10;    // sets x to 10
  static assert(!__traits(compiles, min(3, y) = 10));
  static assert(!__traits(compiles, min(y, 3) = 10));
}

Recursive Templates

Template features can be combined to produce some interesting effects, such as compile time evaluation of non-trivial functions. For example, a factorial template can be written:

template factorial(int n : 1) {
  enum { factorial = 1 }
}

template factorial(int n) {
  enum { factorial = n* factorial!(n-1) }
}

void test() {
  writefln("%s", factorial!(4)); // prints 24
}

Template Constraints

Constraint:
    if ( ConstraintExpression )

ConstraintExpression:
    Expression

Constraints are used to impose additional constraints on matching arguments to a template beyond what is possible in the TemplateParameterList. The ConstraintExpression is computed at compile time and returns a result that is converted to a boolean value. If that value is true, then the template is matched, otherwise the template is not matched.

For example, the following function template only matches with odd values of N:

void foo(int N)()
        if (N & 1)
{
  ...
}
...
foo!(3)();  // ok, matches
foo!(4)();  // error, no match

Limitations

Templates cannot be used to add non-static members or virtual functions to classes. For example:

class Foo {
  template TBar(T) {
    T xx;               // becomes a static member of Foo
    int func(T) { ... } // non-virtual

    static T yy;                        // Ok
    static int func(T t, int y) { ... } // Ok
  }
}

Templates cannot be declared inside functions.

Templates cannot add functions to interfaces:

interface TestInterface { void tpl(T)(); }   // error
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Mixins - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Mixins

A TemplateMixin takes an arbitrary set of declarations from the body of a TemplateDeclaration and inserts them into the current context.
TemplateMixinDeclaration:
    mixin template TemplateIdentifier ( TemplateParameterList ) Constraintopt
        { DeclDefs }

TemplateMixin:
    mixin TemplateIdentifier ;
    mixin TemplateIdentifier MixinIdentifier ;
    mixin TemplateIdentifier !( TemplateArgumentList ) ;
    mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ;

MixinIdentifier:
    Identifier

A TemplateMixin can occur in declaration lists of modules, classes, structs, unions, and as a statement. The TemplateIdentifier refers to a TemplateDeclaration. If the TemplateDeclaration has no parameters, the mixin form that has no !(TemplateArgumentList) can be used.

Unlike a template instantiation, a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined. It is analogous to cutting and pasting the body of the template into the location of the mixin. It is useful for injecting parameterized ‘boilerplate’ code, as well as for creating templated nested functions, which is not possible with template instantiations.

mixin template Foo() {
  int x = 5;
}

mixin Foo;

struct Bar {
  mixin Foo;
}

void test() {
  writefln("x = %d", x);  // prints 5
  {
    Bar b;
    int x = 3;

    writefln("b.x = %d", b.x); // prints 5
    writefln("x = %d", x);     // prints 3
    {
      mixin Foo;
      writefln("x = %d", x);   // prints 5
      x = 4;
      writefln("x = %d", x);   // prints 4
    }
    writefln("x = %d", x);     // prints 3
  }
  writefln("x = %d", x);       // prints 5
}
Mixins can be parameterized:
mixin template Foo(T) {
  T x = 5;
}

mixin Foo!(int);           // create x of type int
Mixins can add virtual functions to a class:
mixin template Foo() {
  void func() { writefln("Foo.func()"); }
}

class Bar {
  mixin Foo;
}

class Code : Bar {
  override void func() { writefln("Code.func()"); }
}

void test() {
  Bar b = new Bar();
  b.func();      // calls Foo.func()

  b = new Code();
  b.func();      // calls Code.func()
}
Mixins are evaluated in the scope of where they appear, not the scope of the template declaration:
int y = 3;

mixin template Foo() {
  int abc() { return y; }
}

void test() {
  int y = 8;
  mixin Foo; // local y is picked up, not global y
  assert(abc() == 8);
}
Mixins can parameterize symbols using alias parameters:
mixin template Foo(alias b) {
  int abc() { return b; }
}

void test() {
  int y = 8;
  mixin Foo!(y);
  assert(abc() == 8);
}
This example uses a mixin to implement a generic Duff's device for an arbitrary statement (in this case, the arbitrary statement is in bold). A nested function is generated as well as a delegate literal, these can be inlined by the compiler:
mixin template duffs_device(alias id1, alias id2, alias s)
{
  void duff_loop()
  {
    if (id1 < id2)
    {
      typeof(id1) n = (id2 - id1 + 7) / 8;
      switch ((id2 - id1) % 8)
      {
        case 0: do { s(); goto case;
        case 7:      s(); goto case;
        case 6:      s(); goto case;
        case 5:      s(); goto case;
        case 4:      s(); goto case;
        case 3:      s(); goto case;
        case 2:      s(); goto case;
        case 1:      s(); continue;
        default:     assert(0, "Impossible");
                } while (--n > 0);
      }
    }
  }
}

void foo() { writefln("foo"); }

void test() {
  int i = 1;
  int j = 11;

  mixin duffs_device!(i, j, delegate { foo(); } );
  duff_loop();  // executes foo() 10 times
}

Mixin Scope

The declarations in a mixin are ‘imported’ into the surrounding scope. If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one:
int x = 3;

mixin template Foo() {
  int x = 5;
  int y = 5;
}

mixin Foo;
int y = 3;

void test() {
  writefln("x = %d", x);  // prints 3
  writefln("y = %d", y);  // prints 3
}
If two different mixins are put in the same scope, and each define a declaration with the same name, there is an ambiguity error when the declaration is referenced:
mixin template Foo() {
  int x = 5;
  void func(int x) { }
}

mixin template Bar() {
  int x = 4;
  void func() { }
}

mixin Foo;
mixin Bar;

void test() {
  writefln("x = %d", x); // error, x is ambiguous
  func();             // error, func is ambiguous
}

The call to func() is ambiguous because Foo.func and Bar.func are in different scopes.

If a mixin has a MixinIdentifier, it can be used to disambiguate:

int x = 6;

mixin template Foo() {
  int x = 5;
  int y = 7;
  void func() { }
}

mixin template Bar() {
  int x = 4;
  void func() { }
}

mixin Foo F;
mixin Bar B;

void test() {
  writefln("y = %d", y);     // prints 7
  writefln("x = %d", x);     // prints 6
  writefln("F.x = %d", F.x); // prints 5
  writefln("B.x = %d", B.x); // prints 4
  F.func();                  // calls Foo.func
  B.func();                  // calls Bar.func
}

Alias declarations can be used to overload together functions declared in different mixins:

mixin template Foo() {
  void func(int x) {  }
}

mixin template Bar() {
  void func() {  }
}

mixin Foo!() F;
mixin Bar!() B;

alias F.func func;
alias B.func func;

void main() {
  func();  // calls B.func
  func(1); // calls F.func
}

A mixin has its own scope, even if a declaration is overridden by the enclosing one:

int x = 4;

mixin template Foo() {
  int x = 5;
  int bar() { return x; }
}

mixin Foo;

void test() {
  writefln("x = %d", x);         // prints 4
  writefln("bar() = %d", bar()); // prints 5
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Contract Programming - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Contract Programming

Contracts are a breakthrough technique to reduce the programming effort for large projects. Contracts are the concept of preconditions, postconditions, errors, and invariants. Contracts can be done in C++ without modification to the language, but the result is clumsy and inconsistent.

Building contract support into the language makes for:

  1. a consistent look and feel for the contracts
  2. tool support
  3. it's possible the compiler can generate better code using information gathered from the contracts
  4. easier management and enforcement of contracts
  5. handling of contract inheritance

The idea of a contract is simple - it's just an expression that must evaluate to true. If it does not, the contract is broken, and by definition, the program has a bug in it. Contracts form part of the specification for a program, moving it from the documentation to the code itself. And as every programmer knows, documentation tends to be incomplete, out of date, wrong, or non-existent. Moving the contracts into the code makes them verifiable against the program.

Assert Contract

The most basic contract is the AssertExpression. An assert inserts a checkable expression into the code, and that expression must evaluate to true:
assert(expression);
C programmers will find it familiar. Unlike C, however, an assert in function bodies works by throwing an AssertError, which can be caught and handled. Catching the contract violation is useful when the code must deal with errant uses by other code, when it must be failure proof, and as a useful tool for debugging.

Pre and Post Contracts

The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has. The syntax is:
in
{
  ...contract preconditions...
}
out (result)
{
  ...contract postconditions...
}
body
{
  ...code...
}
By definition, if a pre contract fails, then the body received bad parameters. An AssertError is thrown. If a post contract fails, then there is a bug in the body. An AssertError is thrown.

Either the in or the out clause can be omitted. If the out clause is for a function body, the variable result is declared and assigned the return value of the function. For example, let's implement a square root function:

long square_root(long x)
  in
  {
    assert(x >= 0);
  }
  out (result)
  {
    assert((result * result) <= x && (result+1) * (result+1) >= x);
  }
  body
  {
    return cast(long)std.math.sqrt(cast(real)x);
  }
The assert's in the in and out bodies are called contracts. Any other D statement or expression is allowed in the bodies, but it is important to ensure that the code has no side effects, and that the release version of the code will not depend on any effects of the code. For a release build of the code, the in and out code is not inserted.

If the function returns a void, there is no result, and so there can be no result declaration in the out clause. In that case, use:

void func()
  out
  {
    ...contracts...
  }
  body
  {
    ...
  }
In an out statement, result is initialized and set to the return value of the function.

In, Out and Inheritance

If a function in a derived class overrides a function in its super class, then only one of the in contracts of the function and its base functions must be satisfied. Overriding functions then becomes a process of loosening the in contracts.

A function without an in contract means that any values of the function parameters are allowed. This implies that if any function in an inheritance hierarchy has no in contract, then in contracts on functions overriding it have no useful effect.

Conversely, all of the out contracts needs to be satisfied, so overriding functions becomes a processes of tightening the out contracts.

Invariants

Invariants are used to specify characteristics of a class or struct that always must be true (except while executing a member function). For example, a class representing a date might have an invariant that the day must be 1..31 and the hour must be 0..23:

class Date
{
  int day;
  int hour;

  invariant() {
    assert(1 <= day && day <= 31);
    assert(0 <= hour && hour < 24);
  }
}

The invariant is a contract saying that the asserts must hold true. The invariant is checked when a class or struct constructor completes, at the start of the class or struct destructor. For public or exported functions, the order of execution is:

  1. preconditions
  2. invariant
  3. body
  4. invariant
  5. postconditions

The code in the invariant may not call any public non-static members of the class or struct, either directly or indirectly. Doing so will result in a stack overflow, as the invariant will wind up being called in an infinitely recursive manner.

Invariants are implicitly const.

Since the invariant is called at the start of public or exported members, such members should not be called from constructors.

class Foo {
  public void f() { }
  private void g() { }

  invariant() {
    f();  // error, cannot call public member function from invariant
    g();  // ok, g() is not public
  }
}
The invariant can be checked with an assert() expression:
  1. classes need to pass a class object
  2. structs need to pass the address of an instance
auto mydate = new Date(); //class
auto s = S();             //struct
...
assert(mydate);           // check that class Date invariant holds
assert(&s);               // check that struct S invariant holds
Invariants contain assert expressions, and so when they fail, they throw a AssertErrors. Class invariants are inherited, that is, any class invariant is implicitly anded with the invariants of its base classes.

There can be only one Invariant per class or struct.

When compiling for release, the invariant code is not generated, and the compiled program runs at maximum speed.

References

  • Contracts Reading List
  • Adding Contracts to Java
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Conditional Compilation - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Conditional Compilation

Conditional compilation is the process of selecting which code to compile and which code to not compile. (In C and C++, conditional compilation is done with the preprocessor directives #if / #else / #endif.)

ConditionalDeclaration:
    Condition CCDeclarationBlock
    Condition CCDeclarationBlock else CCDeclarationBlock
    Condition : Declarations

CCDeclarationBlock:
    Declaration
    { Declarations }
    { }

Declarations:
    Declaration
    Declaration Declarations

ConditionalStatement:
    Condition NoScopeNonEmptyStatement
    Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement

If the Condition is satisfied, then the following CCDeclarationBlock or Statement is compiled in. If it is not satisfied, the CCDeclarationBlock or Statement after the optional else is compiled in.

Any CCDeclarationBlock or Statement that is not compiled in still must be syntactically correct.

No new scope is introduced, even if the CCDeclarationBlock or Statement is enclosed by { }.

ConditionalDeclarations and ConditionalStatements can be nested.

The StaticAssert can be used to issue errors at compilation time for branches of the conditional compilation that are errors.

Condition comes in the following forms:

Condition:
    VersionCondition
    DebugCondition
    StaticIfCondition

Version Condition

VersionCondition:
    version ( IntegerLiteral )
    version ( Identifier )
   version ( unittest )

Versions enable multiple versions of a module to be implemented with a single source file.

The VersionCondition is satisfied if the IntegerLiteral is greater than or equal to the current version level, or if Identifier matches a version identifier.

The version level and version identifier can be set on the command line by the -version switch or in the module itself with a VersionSpecification, or they can be predefined by the compiler.

Version identifiers are in their own unique name space, they do not conflict with debug identifiers or other symbols in the module. Version identifiers defined in one module have no influence over other imported modules.

int k;
version (Demo) // compile in this code block for the demo version
{ int i;
  int k;    // error, k already defined

  i = 3;
}
x = i;      // uses the i declared above

version (X86)
{
  ... // implement custom inline assembler version
}
else
{
  ... // use default, but slow, version
}

The version(unittest) is satisfied if and only if the code is compiled with unit tests enabled (the -unittest option on dmd).

Version Specification

VersionSpecification:
    version = Identifier ;
    version = IntegerLiteral ;

The version specification makes it straightforward to group a set of features under one major version, for example:

version (ProfessionalEdition)
{
  version = FeatureA;
  version = FeatureB;
  version = FeatureC;
}
version (HomeEdition)
{
  version = FeatureA;
}
...
version (FeatureB)
{
  ... implement Feature B ...
}

Version identifiers or levels may not be forward referenced:

version (Foo)
{
  int x;
}
version = Foo;	// error, Foo already used

VersionSpecifications may only appear at module scope.

While the debug and version conditions superficially behave the same, they are intended for very different purposes. Debug statements are for adding debug code that is removed for the release version. Version statements are to aid in portability and multiple release versions.

Here's an example of a full version as opposed to a demo version:

class Foo {
  int a, b;

  version(full)
  {
    int extrafunctionality()
    {
      ...
      return 1;  // extra functionality is supported
    }
  }
  else // demo
  {
    int extrafunctionality()
    {
      return 0;  // extra functionality is not supported
    }
  }
}
Various different version builds can be built with a parameter to version:
version(n) // add in version code if version level is &gt;= n
{
   ... version code ...
}

version(identifier) // add in version code if version
                         // keyword is identifier
{
   ... version code ...
}

These are presumably set by the command line as -version=n and -version=identifier.

Predefined Versions

Several environmental version identifiers and identifier name spaces are predefined for consistent usage. Version identifiers do not conflict with other identifiers in the code, they are in a separate name space. Predefined version identifiers are global, i.e. they apply to all modules being compiled and imported.

Predefined Version Identifiers
Version Identifier | Description
DigitalMars | DMD (Digital Mars D) is the compiler
GNU | GDC (GNU D Compiler) is the compiler
LDC | LDC (LLVM D Compiler) is the compiler
SDC | SDC (Stupid D Compiler) is the compiler
Windows | Microsoft Windows systems
Win32 | Microsoft 32-bit Windows systems
Win64 | Microsoft 64-bit Windows systems
linux | All Linux systems
OSX | Mac OS X
FreeBSD | FreeBSD
OpenBSD | OpenBSD
NetBSD | NetBSD
DragonFlyBSD | DragonFlyBSD
BSD | All other BSDs
Solaris | Solaris
Posix | All POSIX systems (includes Linux, FreeBSD, OS X, Solaris, etc.)
AIX | IBM Advanced Interactive eXecutive OS
Haiku | The Haiku operating system
SkyOS | The SkyOS operating system
SysV3 | System V Release 3
SysV4 | System V Release 4
Hurd | GNU Hurd
Android | The Android platform
Cygwin | The Cygwin environment
MinGW | The MinGW environment
X86 | Intel and AMD 32-bit processors
X86_64 | Intel and AMD 64-bit processors
ARM | The ARM architecture (32-bit) (AArch32:A32)
ARM_Thumb | ARM in Thumb mode (AArch32:T32)
ARM_Soft | The ARM soft floating point ABI
ARM_SoftFP | The ARM softfp floating point ABI
ARM_HardFP | The ARM hardfp floating point ABI
ARM64 | The Advanced RISC Machine architecture (64-bit) (AArch64:A64)
PPC | The PowerPC architecture, 32-bit
PPC_SoftFP | The PowerPC soft float ABI
PPC_HardFP | The PowerPC hard float ABI
PPC64 | The PowerPC architecture, 64-bit
IA64 | The Itanium architecture (64-bit)
MIPS | The MIPS architecture
MIPS32 | The MIPS architecture, 32-bit
MIPS64 | The MIPS architecture, 64-bit
MIPS_O32 | The MIPS O32 ABI
MIPS_N32 | The MIPS N32 ABI
MIPS_O64 | The MIPS O64 ABI
MIPS_N64 | The MIPS N64 ABI
MIPS_EABI | The MIPS EABI
MIPS_NoFloat | The MIPS no-float ABI
MIPS_SoftFloat | The MIPS soft-float ABI
MIPS_HardFloat | The MIPS hard-float ABI
SPARC | The SPARC architecture, 32-bit
SPARC_V8Plus | The SPARC v8+ ABI
SPARC_SoftFP | The SPARC soft float ABI
SPARC_HardFP | The SPARC hard float ABI
SPARC64 | The SPARC architecture, 64-bit
S390 | The System/390 architecture, 32-bit
S390X | The System/390X architecture, 64-bit
HPPA | The HP PA-RISC architecture, 32-bit
HPPA64 | The HP PA-RISC architecture, 64-bit
SH | The SuperH architecture, 32-bit
SH64 | The SuperH architecture, 64-bit
Alpha | The Alpha architecture
Alpha_SoftFP | The Alpha soft float ABI
Alpha_HardFP | The Alpha hard float ABI
LittleEndian | Byte order, least significant first
BigEndian | Byte order, most significant first
D_Coverage | Code coverage analysis instrumentation (command line switch -cov) is being generated
D_Ddoc | Ddoc documentation (command line switch -D) is being generated
D_InlineAsm_X86 | Inline assembler for X86 is implemented
D_InlineAsm_X86_64 | Inline assembler for X86-64 is implemented
D_LP64 | Pointers are 64 bits (command line switch -m64)
D_X32 | Pointers are 32 bits, but words are still 64 bits (x32 ABI)
D_HardFloat | The target hardware has a floating point unit
D_SoftFloat | The target hardware does not have a floating point unit
D_PIC | Position Independent Code (command line switch -fPIC) is being generated
D_SIMD | Vector extensions (via __simd) are supported
D_Version2 | This is a D version 2 compiler
D_NoBoundsChecks | Array bounds checks are disabled (command line switch -noboundscheck)
unittest | Unit tests are enabled (command line switch -unittest)
assert | assert expressions are enabled
none | Never defined; used to just disable a section of code
all | Always defined; used as the opposite of none

The following identifiers are defined, but are deprecated:

Predefined Version Identifiers
Version Identifier | Description
darwin | The Darwin operating system; use OSX instead
Thumb | ARM in Thumb mode; use ARM_Thumb instead

Others will be added as they make sense and new implementations appear.

It is inevitable that the D language will evolve over time. Therefore, the version identifier namespace beginning with "D_" is reserved for identifiers indicating D language specification or new feature conformance. Further, all identifiers derived from the ones listed above by appending any character(s) are reserved. This means that e.g. ARM_foo and Windows_bar are reserved while foo_ARM and bar_Windows are not.

Furthermore, predefined version identifiers from this list cannot be set from the command line or from version statements. (This prevents things like both Windows and linux being simultaneously set.)

Compiler vendor specific versions can be predefined if the trademarked vendor identifier prefixes it, as in:

version(DigitalMars_funky_extension)
{
    ...
}

It is important to use the right version identifier for the right purpose. For example, use the vendor identifier when using a vendor specific feature. Use the operating system identifier when using an operating system specific feature, etc.

Debug Condition

DebugCondition:
    debug
    debug ( IntegerLiteral )
    debug ( Identifier )

Two versions of programs are commonly built, a release build and a debug build. The debug build includes extra error checking code, test harnesses, pretty-printing code, etc. The debug statement conditionally compiles in its statement body. It is D's way of what in C is done with #ifdef DEBUG / #endif pairs.

The debug condition is satisfied when the -debug switch is thrown on the compiler.

The debug ( IntegerLiteral ) condition is satisfied when the debug level is >= IntegerLiteral.

The debug ( Identifier ) condition is satisfied when the debug identifier matches Identifier.

class Foo {
  int a, b;
 debug:
  int flag;
}

Debug Specification

DebugSpecification:
    debug = Identifier ;
    debug = IntegerLiteral ;

Debug identifiers and levels are set either by the command line switch -debug or by a DebugSpecification.

Debug specifications only affect the module they appear in, they do not affect any imported modules. Debug identifiers are in their own namespace, independent from version identifiers and other symbols.

It is illegal to forward reference a debug specification:

debug (foo) writefln("Foo");
debug = foo;	// error, foo used before set

DebugSpecifications may only appear at module scope.

Various different debug builds can be built with a parameter to debug:

debug(IntegerLiteral) { }    // add in debug code if debug level is &gt;= IntegerLiteral
debug(identifier) { } // add in debug code if debug keyword is identifier

These are presumably set by the command line as -debug=n and -debug=identifier.

Static If Condition

StaticIfCondition:
    static if ( AssignExpression )

AssignExpression is implicitly converted to a boolean type, and is evaluated at compile time. The condition is satisfied if it evaluates to true. It is not satisfied if it evaluates to false.

It is an error if AssignExpression cannot be implicitly converted to a boolean type or if it cannot be evaluated at compile time.

StaticIfConditions can appear in module, class, template, struct, union, or function scope. In function scope, the symbols referred to in the AssignExpression can be any that can normally be referenced by an expression at that point.

const int i = 3;
int j = 4;

static if (i == 3)	// ok, at module scope
    int x;

class C {
  const int k = 5;

  static if (i == 3) // ok
    int x;
  else
    long x;

  static if (j == 3) // error, j is not a constant
    int y;

  static if (k == 5) // ok, k is in current scope
    int z;
}

template INT(int i) {
  static if (i == 32)
    alias int INT;
  else static if (i == 16)
    alias short INT;
  else
    static assert(0); // not supported
}

INT!(32) a;  // a is an int
INT!(16) b;  // b is a short
INT!(17) c;  // error, static assert trips

A StaticIfConditional condition differs from an IfStatement in the following ways:

  1. It can be used to conditionally compile declarations, not just statements.
  2. It does not introduce a new scope even if { } are used for conditionally compiled statements.
  3. For unsatisfied conditions, the conditionally compiled code need only be syntactically correct. It does not have to be semantically correct.
  4. It must be evaluatable at compile time.

Static Assert

StaticAssert:
    static assert ( AssignExpression );
    static assert ( AssignExpression , AssignExpression );

AssignExpression is evaluated at compile time, and converted to a boolean value. If the value is true, the static assert is ignored. If the value is false, an error diagnostic is issued and the compile fails.

Unlike AssertExpressions, StaticAsserts are always checked and evaluted by the compiler unless they appear in an unsatisfied conditional.

void foo() {
  if (0)
  {
    assert(0);  // never trips
    static assert(0); // always trips
  }
  version (BAR)
  {
  }
  else
  {
    static assert(0); // trips when version BAR is not defined
  }
}

StaticAssert is useful tool for drawing attention to conditional configurations not supported in the code.

The optional second AssignExpression can be used to supply additional information, such as a text string, that will be printed out along with the error diagnostic.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Vector Extensions - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Vector Extensions

Modern CPUs often support specialized vector types and vector operations, sometimes called "media instructions". Vector types are a fixed array of floating or integer types, and vector operations operate simultaneously on them, thus achieving great speedups.

When the compiler takes advantage of these instructions with standard D code to speed up loops over arithmetic data, this is called auto-vectorization. Auto-vectorization, however, has had only limited success and has not been able to really take advantage of the richness (and often quirkiness) of the native vector instructions.

D has the array operation notation, such as:

int[] a,b;
...
a[] += b[];

which can be vectorized by the compiler, but again success is limited for the same reason auto-vectorization is.

The difficulties with trying to use vector instructions on regular arrays are:

  1. The vector types have stringent alignment requirements that are not and cannot be met by conventional arrays.
  2. C ABI's often have vector extensions and have special name mangling for them, call/return conventions, and symbolic debug support.
  3. The only way to get at the full vector instruction set would be to use inline assembler - but the compiler cannot do register allocation across inline assembler blocks (or other optimizations), leading to poor code performance.
  4. Interleaving conventional array code with vector operations on the same data can unwittingly lead to extremely poor runtime performance.

These issues are cleared up by using special vector types.

core.simd

Vector types and operations are introduced to D code by importing core.simd:

import core.simd;

These types and operations will be the ones defined for the architecture the compiler is targetting. If a particular CPU family has varying support for vector types, an additional runtime check may be necessary. The compiler does not emit runtime checks; those must be done by the programmer.

The types defined will all follow the naming convention:

typeNN

where type is the vector element type and NN is the number of those elements in the vector type. The type names will not be keywords.

Properties

Vector types have the property:

Vector Type Properties
Property | Description
.array | Returns static array representation

All the properties of the static array representation also work.

Conversions

Vector types of the same size can be implicitly converted among each other. Vector types can be cast to the static array representation.

Integers and floating point values can be implicitly converted to their vector equivalents:

int4 v = 7;
v = 3 * v;   // multiply each element in v by 3

Accessing Individual Vector Elements

They cannot be accessed directly, but can be when converted to an array type:

int4 v;
(cast(int*)&v)[3] = 2;   // set 3rd element of the 4 int vector
cast(int[4])v[3] = 2;    // set 3rd element of the 4 int vector
v.array[3] = 2;          // set 3rd element of the 4 int vector
v.ptr[3] = 2;            // set 3rd element of the 4 int vector

Conditional Compilation

If vector extensions are implemented, the version identifier D_SIMD is set.

Whether a type exists or not can be tested at compile time with an IsExpression:

static if (is(typeNN))
    ... yes, it is supported ...
else
    ... nope, use workaround ...

Whether a particular operation on a type is supported can be tested at compile time with:

float4 a,b;
static if (__traits(compiles, a+b))
    ... yes, it is supported ...
else
    ... nope, use workaround ...

For runtime testing to see if certain vector instructions are available, see the functions in core.cpuid.

A typical workaround would be to use array vector operations instead:

float4 a,b;
static if (__traits(compiles, a/b))
    c = a / b;
else
    c[] = a[] / b[];

X86 And X86_64 Vector Extension Implementation

The rest of this document describes the specific implementation of the vector types for the X86 and X86_64 architectures.

The vector extensions are currently implemented for the OS X 32 bit target, and all 64 bit targets.

core.simd defines the following types:

Vector Types
Type Name | Description | gcc Equivalent
void16 | 16 bytes of untyped data | no equivalent
byte16 | 16 byte's | signed char __attribute((vector_size(16)))
ubyte16 | 16 ubyte's | unsigned char __attribute((vector_size(16)))
short8 | 8 short's | short __attribute((vector_size(16)))
ushort8 | 8 ushort's | ushort __attribute((vector_size(16)))
int4 | 4 int's | int __attribute((vector_size(16)))
uint4 | 4 uint's | unsigned __attribute((vector_size(16)))
long2 | 2 long's | long __attribute((vector_size(16)))
ulong2 | 2 ulong's | unsigned long __attribute((vector_size(16)))
float4 | 4 float's | float __attribute((vector_size(16)))
double2 | 2 double's | double __attribute((vector_size(16)))

Note: for 32 bit gcc, it's long long instead of long.

Supported Vector Operators
Operator | void16 | byte16 | ubyte16 | short8 | ushort8 | int4 | uint4 | long2 | ulong2 | float4 | double2
= | × | × | × | × | × | × | × | × | × | × | ×
+ += | – | × | × | × | × | × | × | × | × | × | ×
- -= | – | × | × | × | × | × | × | × | × | × | ×
* *= | – | – | – | × | × | – | – | – | – | × | ×
/ /= | – | – | – | – | – | – | – | – | – | × | ×
& &= | – | × | × | × | × | × | × | × | × | – | –
| |= | – | × | × | × | × | × | × | × | × | – | –
^ ^= | – | × | × | × | × | × | × | × | × | – | –
unary~ | – | × | × | × | × | × | × | × | × | – | –
unary+ | – | × | × | × | × | × | × | × | × | × | ×
unary- | – | × | × | × | × | × | × | × | × | × | ×

Operators not listed are not supported at all.

Vector Operation Intrinsics

See core.simd for the supported intrinsics.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Traits - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Traits

Traits are extensions to the language to enable programs, at compile time, to get at information internal to the compiler. This is also known as compile time reflection. It is done as a special, easily extended syntax (similar to Pragmas) so that new capabilities can be added as required.

TraitsExpression:
    __traits ( TraitsKeyword , TraitsArguments )

TraitsKeyword:
    isAbstractClass
    isArithmetic
    isAssociativeArray
    isFinalClass
    isFloating
    isIntegral
    isScalar
    isStaticArray
    isUnsigned
    isVirtualFunction
    isVirtualMethod
    isAbstractFunction
    isFinalFunction
    isStaticFunction
    isRef
    isOut
    isLazy
    hasMember
    identifier
    getMember
    getOverloads
    getProtection
    getVirtualFunctions
    getVirtualMethods
    parent
    classInstanceSize
    allMembers
    derivedMembers
    isSame
    compiles

TraitsArguments:
    TraitsArgument
    TraitsArgument , TraitsArguments

TraitsArgument:
    AssignExpression
    Type

isArithmetic

If the arguments are all either types that are arithmetic types, or expressions that are typed as arithmetic types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

void main() {
  int i;
  writeln(__traits(isArithmetic, int));
  writeln(__traits(isArithmetic, i, i+1, int));
  writeln(__traits(isArithmetic));
  writeln(__traits(isArithmetic, int*));
}

Prints:

true
true
false
false

isFloating

Works like isArithmetic, except it's for floating point types (including imaginary and complex types).

isIntegral

Works like isArithmetic, except it's for integral types (including character types).

isScalar

Works like isArithmetic, except it's for scalar types.

isUnsigned

Works like isArithmetic, except it's for unsigned types.

isStaticArray

Works like isArithmetic, except it's for static array types.

isAssociativeArray

Works like isArithmetic, except it's for associative array types.

isAbstractClass

If the arguments are all either types that are abstract classes, or expressions that are typed as abstract classes, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

abstract class C { int foo(); }

void main() {
  C c;
  writeln(__traits(isAbstractClass, C));
  writeln(__traits(isAbstractClass, c, C));
  writeln(__traits(isAbstractClass));
  writeln(__traits(isAbstractClass, int*));
}

Prints:

true
true
false
false

isFinalClass

Works like isAbstractClass, except it's for final classes.

isVirtualFunction

The same as isVirtualMethod, except that final functions that don't override anything return true.

isVirtualMethod

Takes one argument. If that argument is a virtual function, true is returned, otherwise false. Final functions that don't override anything return false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

void main() {
  writeln(__traits(isVirtualMethod, C.bar));  // true
  writeln(__traits(isVirtualMethod, S.bar));  // false
}

isAbstractFunction

Takes one argument. If that argument is an abstract function, true is returned, otherwise false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

class AC {
  abstract void foo();
}

void main() {
  writeln(__traits(isAbstractFunction, C.bar));   // false
  writeln(__traits(isAbstractFunction, S.bar));   // false
  writeln(__traits(isAbstractFunction, AC.foo));  // true
}

isFinalFunction

Takes one argument. If that argument is a final function, true is returned, otherwise false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
  final void foo();
}

final class FC {
  void foo();
}

void main() {
  writeln(__traits(isFinalFunction, C.bar));	  // false
  writeln(__traits(isFinalFunction, S.bar));	  // false
  writeln(__traits(isFinalFunction, C.foo));	  // true
  writeln(__traits(isFinalFunction, FC.foo));  // true
}

isStaticFunction

Takes one argument. If that argument is a static function, meaning it has no context pointer, true is returned, otherwise false.

isRef, isOut, isLazy

Takes one argument. If that argument is a declaration, true is returned if it is ref, out, or lazy, otherwise false.

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

hasMember

The first argument is a type that has members, or is an expression of a type that has members. The second argument is a string. If the string is a valid property of the type, true is returned, otherwise false.

import std.stdio;

struct S {
  int m;
}

void main() {
  S s;

  writeln(__traits(hasMember, S, "m")); // true
  writeln(__traits(hasMember, s, "m")); // true
  writeln(__traits(hasMember, S, "y")); // false
  writeln(__traits(hasMember, int, "sizeof")); // true
}

identifier

Takes one argument, a symbol. Returns the identifier for that symbol as a string literal.

getMember

Takes two arguments, the second must be a string. The result is an expression formed from the first argument, followed by a ‘.’, followed by the second argument as an identifier.

import std.stdio;

struct S {
  int mx;
  static int my;
}

void main() {
  S s;

  __traits(getMember, s, "mx") = 1;  // same as s.mx=1;
  writeln(__traits(getMember, s, "m" ~ "x")); // 1

  __traits(getMember, S, "mx") = 1;  // error, no this for S.mx
  __traits(getMember, S, "my") = 2;  // ok
}

getOverloads

The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is a tuple of all the overloads of that function.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getOverloads, D, "foo"))
    writeln(typeid(typeof(t)));

  alias typeof(__traits(getOverloads, D, "foo")) b;
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getOverloads, d, "foo")[1](1);
  writeln(i);
}

Prints:

void()
int()
void()
int()
2

getProtection

The argument is a symbol. The result is a string giving its protection level: "public", "private", "protected", "export", or "package".

import std.stdio;

class D {
  export void foo() { }
  public int bar;
}

void main() {
  D d = new D();

  auto i = __traits(getProtection, d.foo);
  writeln(i);

  auto j = __traits(getProtection, d.bar);
  writeln(j);
}

Prints:

export
public

getVirtualFunctions

The same as getVirtualMethods, except that final functions that do not override anything are included.

getVirtualMethods

The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is a tuple of the virtual overloads of that function. It does not include final functions that do not override anything.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getVirtualMethods, D, "foo"))
    writeln(typeid(typeof(t)));

  alias typeof(__traits(getVirtualMethods, D, "foo")) b;
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getVirtualMethods, d, "foo")[1](1);
  writeln(i);
}

Prints:

void()
int()
void()
int()
2

parent

Takes a single argument which must evaluate to a symbol. The result is the symbol that is the parent of it.

classInstanceSize

Takes a single argument, which must evaluate to either a class type or an expression of class type. The result is of type size_t, and the value is the number of bytes in the runtime instance of the class type. It is based on the static type of a class, not the polymorphic type.

allMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type combined with all of the members of the base classes (if the type is a class). No name is repeated. Builtin properties are not included.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto b = [ __traits(allMembers, D) ];
  writeln(b);
  // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]
}

The order in which the strings appear in the result is not defined.

derivedMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type. No name is repeated. Base class member names are not included. Builtin properties are not included.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto a = [__traits(derivedMembers, D)];
  writeln(a);    // ["__ctor", "__dtor", "foo"]
}

The order in which the strings appear in the result is not defined.

isSame

Takes two arguments and returns bool true if they are the same symbol, false if not.

import std.stdio;

struct S { }

int foo();
int bar();

void main() {
  writeln(__traits(isSame, foo, foo)); // true
  writeln(__traits(isSame, foo, bar)); // false
  writeln(__traits(isSame, foo, S));   // false
  writeln(__traits(isSame, S, S));     // true
  writeln(__traits(isSame, std, S));   // false
  writeln(__traits(isSame, std, std)); // true
}

If the two arguments are expressions made up of literals or enums that evaluate to the same value, true is returned.

compiles

Returns a bool true if all of the arguments compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. The arguments cannot be statements or declarations.

If there are no arguments, the result is false.

import std.stdio;

struct S {
  static int s1;
  int s2;
}

int foo();
int bar();

void main() {
  writeln(__traits(compiles));                      // false
  writeln(__traits(compiles, foo));                 // true
  writeln(__traits(compiles, foo + 1));             // true
  writeln(__traits(compiles, &foo + 1));            // false
  writeln(__traits(compiles, typeof(1)));           // true
  writeln(__traits(compiles, S.s1));                // true
  writeln(__traits(compiles, S.s3));                // false
  writeln(__traits(compiles, 1,2,3,int,long,std));  // true
  writeln(__traits(compiles, 3[1]));                // false
  writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false
}

This is useful for:

  • Giving better error messages inside generic code than the sometimes hard to follow compiler ones.
  • Doing a finer grained specialization than template partial specialization allows for.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Errors - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Errors

I came, I coded, I crashed.

Julius C'ster
All programs have to deal with errors. Errors are unexpected conditions that are not part of the normal operation of a program. Examples of common errors are:
  • Out of memory.
  • Out of disk space.
  • Invalid file name.
  • Attempting to write to a read-only file.
  • Attempting to read a non-existent file.
  • Requesting a system service that is not supported.

The Error Handling Problem

The traditional C way of detecting and reporting errors is not traditional, it is ad-hoc and varies from function to function, including:
  • Returning a NULL pointer.
  • Returning a 0 value.
  • Returning a non-zero error code.
  • Requiring errno to be checked.
  • Requiring that a function be called to check if the previous function failed.
To deal with these possible errors, tedious error handling code must be added to each function call. If an error happened, code must be written to recover from the error, and the error must be reported to the user in some user friendly fashion. If an error cannot be handled locally, it must be explicitly propagated back to its caller. The long list of errno values needs to be converted into appropriate text to be displayed. Adding all the code to do this can consume a large part of the time spent coding a project - and still, if a new errno value is added to the runtime system, the old code can not properly display a meaningful error message.

Good error handling code tends to clutter up what otherwise would be a neat and clean looking implementation.

Even worse, good error handling code is itself error prone, tends to be the least tested (and therefore buggy) part of the project, and is frequently simply omitted. The end result is likely a "blue screen of death" as the program failed to deal with some unanticipated error.

Quick and dirty programs are not worth writing tedious error handling code for, and so such utilities tend to be like using a table saw with no blade guards.

What's needed is an error handling philosophy and methodology such that:

  • It is standardized - consistent usage makes it more useful.
  • The result is reasonable even if the programmer fails to check for errors.
  • Old code can be reused with new code without having to modify the old code to be compatible with new error types.
  • No errors get inadvertently ignored.
  • ‘Quick and dirty’ utilities can be written that still correctly handle errors.
  • It is easy to make the error handling source code look good.

The D Error Handling Solution

Let's first make some observations and assumptions about errors:
  • Errors are not part of the normal flow of a program. Errors are exceptional, unusual, and unexpected.
  • Because errors are unusual, execution of error handling code is not performance critical.
  • The normal flow of program logic is performance critical.
  • All errors must be dealt with in some way, either by code explicitly written to handle them, or by some system default handling.
  • The code that detects an error knows more about the error than the code that must recover from the error.
The solution is to use exception handling to report errors. All errors are objects derived from abstract class Error. class Error has a pure virtual function called toString() which produces a char[] with a human readable description of the error.

If code detects an error like "out of memory," then an Error is thrown with a message saying "Out of memory". The function call stack is unwound, looking for a handler for the Error. Finally blocks are executed as the stack is unwound. If an error handler is found, execution resumes there. If not, the default Error handler is run, which displays the message and terminates the program.

How does this meet our criteria?

It is standardized - consistent usage makes it more useful.
This is the D way, and is used consistently in the D runtime library and examples.
The result is reasonable result even if the programmer fails to check for errors.
If no catch handlers are there for the errors, then the program gracefully exits through the default error handler with an appropriate message.
Old code can be reused with new code without having to modify the old code to be compatible with new error types.
Old code can decide to catch all errors, or only specific ones, propagating the rest upwards. In any case, there is no more need to correlate error numbers with messages, the correct message is always supplied.
No errors get inadvertently ignored.
Error exceptions get handled one way or another. There is nothing like a NULL pointer return indicating an error, followed by trying to use that NULL pointer.
'Quick and dirty' utilities can be written that still correctly handle errors.
Quick and dirty code need not write any error handling code at all, and don't need to check for errors. The errors will be caught, an appropriate message displayed, and the program gracefully shut down all by default.
It is easy to make the error handling source code look good.
The try/catch/finally statements look a lot nicer than endless if (error) goto errorhandler; statements.
How does this meet our assumptions about errors?
Errors are not part of the normal flow of a program. Errors are exceptional, unusual, and unexpected.
D exception handling fits right in with that.
Because errors are unusual, execution of error handling code is not performance critical.
Exception handling stack unwinding is a relatively slow process.
The normal flow of program logic is performance critical.
Since the normal flow code does not have to check every function call for error returns, it can be realistically faster to use exception handling for the errors.
All errors must be dealt with in some way, either by code explicitly written to handle them, or by some system default handling.
If there's no handler for a particular error, it is handled by the runtime library default handler. If an error is ignored, it is because the programmer specifically added code to ignore an error, which presumably means it was intentional.
The code that detects an error knows more about the error than the code that must recover from the error.
There is no more need to translate error codes into human readable strings, the correct string is generated by the error detection code, not the error recovery code. This also leads to consistent error messages for the same error between applications.
Using exceptions to handle errors leads to another issue - how to write exception safe programs. Here's how.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Unit Tests - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Unit Tests

UnitTest:
    unittest FunctionBody

Unit tests are a series of test cases applied to a module to determine if it is working properly. Ideally, unit tests should be run every time a program is compiled.

Unit tests are a special function defined like:

unittest {
  ...test code...
}

There can be any number of unit test functions in a module, including within struct, union and class declarations. They are executed in lexical order. Stylistically, a unit test for a function should appear immediately following it.

A compiler switch, such as -unittest for dmd, will cause the unittest test code to be compiled and incorporated into the resulting executable. The unittest code gets run after static initialization is run and before the main() function is called.

For example, given a class Sum that is used to add two values:

class Sum {
  int add(int x, int y) { return x + y; }

  unittest
  {
    Sum sum = new Sum;
    assert(sum.add(3,4) == 7);
    assert(sum.add(-2,0) == -2);
  }
}

Versioning

The version identifier unittest is predefined if the compilation is done with unit tests enabled.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Garbage Collection - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Garbage Collection

D is a fully garbage collected language. That means that it is never necessary to free memory. Just allocate as needed, and the garbage collector will periodically return all unused memory to the pool of available memory.

C and C++ programmers accustomed to explicitly managing memory allocation and deallocation will likely be skeptical of the benefits and efficacy of garbage collection. Experience both with new projects written with garbage collection in mind, and converting existing projects to garbage collection shows that:

  • Garbage collected programs are often faster. This is counterintuitive, but the reasons are:
    • Reference counting is a common solution to solve explicit memory allocation problems. The code to implement the increment and decrement operations whenever assignments are made is one source of slowdown. Hiding it behind smart pointer classes doesn't help the speed. (Reference counting methods are not a general solution anyway, as circular references never get deleted.)
    • Destructors are used to deallocate resources acquired by an object. For most classes, this resource is allocated memory. With garbage collection, most destructors then become empty and can be discarded entirely.
    • All those destructors freeing memory can become significant when objects are allocated on the stack. For each one, some mechanism must be established so that if an exception happens, the destructors all get called in each frame to release any memory they hold. If the destructors become irrelevant, then there's no need to set up special stack frames to handle exceptions, and the code runs faster.
    • Garbage collection kicks in only when memory gets tight. When memory is not tight, the program runs at full speed and does not spend any time tracing and freeing memory.
    • Garbage collected programs do not suffer from gradual deterioration due to an accumulation of memory leaks.
  • Garbage collectors reclaim unused memory, therefore they do not suffer from "memory leaks" which can cause long running applications to gradually consume more and more memory until they bring down the system. GC programs have longer term stability.
  • Garbage collected programs have fewer hard-to-find pointer bugs. This is because there are no dangling references to freed memory. There is no code to explicitly manage memory, hence no bugs in such code.
  • Garbage collected programs are faster to develop and debug, because there's no need for developing, debugging, testing, or maintaining the explicit deallocation code.

Garbage collection is not a panacea. There are some downsides:

  • It is not easily predictable when a collection gets run, so the program can arbitrarily pause.
  • The time it takes for a collection to run is not bounded. While in practice it is very quick, this cannot be guaranteed.
  • All threads other than the collector thread must be halted while the collection is in progress.
  • Garbage collectors can keep around some memory that an explicit deallocator would not.
  • Garbage collection should be implemented as a basic operating system kernel service. But since it is not, garbage collecting programs must carry around with them the garbage collection implementation. While this can be a shared library, it is still there.

These constraints are addressed by techniques outlined in Memory Management.

How Garbage Collection Works

The GC works by:

  1. Stopping all other threads than the thread currently trying to allocate GC memory.
  2. ‘Hijacking’ the current thread for GC work.
  3. Scanning all ‘root’ memory ranges for pointers into GC allocated memory.
  4. Recursively scanning all allocated memory pointed to by roots looking for more pointers into GC allocated memory.
  5. Freeing all GC allocated memory that has no active pointers to it and do not need destructors to run.
  6. Queueing all unreachable memory that needs destructors to run.
  7. Resuming all other threads.
  8. Running destructors for all queued memory.
  9. Freeing any remaining unreachable memory.
  10. Returning the current thread to whatever work it was doing.

Interfacing Garbage Collected Objects With Foreign Code

The garbage collector looks for roots in:

  1. the static data segment
  2. the stacks and register contents of each thread
  3. the TLS (thread-local storage) areas of each thread
  4. any roots added by core.memory.GC.addRoot() or core.memory.GC.addRange()

If the only pointer to an object is held outside of these areas, then the collector will miss it and free the memory.

To avoid this from happening, either

  • maintain a pointer to the object in an area the collector does scan for pointers;
  • add a root where a pointer to the object is stored using core.memory.GC.addRoot() or core.memory.GC.addRange().
  • reallocate and copy the object using the foreign code's storage allocator or using the C runtime library's malloc/free.

Pointers and the Garbage Collector

Pointers in D can be broadly divided into two categories: Those that point to garbage collected memory, and those that do not. Examples of the latter are pointers created by calls to C's malloc(), pointers received from C library routines, pointers to static data, pointers to objects on the stack, etc. For those pointers, anything that is legal in C can be done with them.

For garbage collected pointers and references, however, there are some restrictions. These restrictions are minor, but they are intended to enable the maximum flexibility in garbage collector design.

Undefined behavior:

  • Do not xor pointers with other values, like the xor pointer linked list trick used in C.
  • Do not use the xor trick to swap two pointer values.
  • Do not store pointers into non-pointer variables using casts and other tricks.
    void* p;
...
int x = cast(int)p;   // error: undefined behavior
    The garbage collector does not scan non-pointer fields for GC pointers.
  • Do not take advantage of alignment of pointers to store bit flags in the low order bits:
    p = cast(void*)(cast(int)p | 1);  // error: undefined behavior
  • Do not store into pointers values that may point into the garbage collected heap:
    p = cast(void*)12345678;   // error: undefined behavior
    A copying garbage collector may change this value.
  • Do not store magic values into pointers, other than null.
  • Do not write pointer values out to disk and read them back in again.
  • Do not use pointer values to compute a hash function. A copying garbage collector can arbitrarily move objects around in memory, thus invalidating the computed hash value.
  • Do not depend on the ordering of pointers:
    if (p1 < p2)  // error: undefined behavior
  ...
    since, again, the garbage collector can move objects around in memory.
  • Do not add or subtract an offset to a pointer such that the result points outside of the bounds of the garbage collected object originally allocated.
    char* p = new char[10];
char* q = p + 6; // ok
q = p + 11;      // error: undefined behavior
q = p - 1;       // error: undefined behavior
  • Do not misalign pointers if those pointers may point into the GC heap, such as:
    struct Foo {
align (1):
  byte b;
  char* p;  // misaligned pointer
}
    Misaligned pointers may be used if the underlying hardware supports them and the pointer is never used to point into the GC heap.
  • Do not use byte-by-byte memory copies to copy pointer values. This may result in intermediate conditions where there is not a valid pointer, and if the gc pauses the thread in such a condition, it can corrupt memory. Most implementations of memcpy() will work since the internal implementation of it does the copy in aligned chunks greater than or equal to the pointer size, but since this kind of implementation is not guaranteed by the C standard, use memcpy() only with extreme caution.
  • Do not have pointers in a struct instance that point back to the same instance. The trouble with this is if the instance gets moved in memory, the pointer will point back to where it came from, with likely disastrous results.

Things that are reliable and can be done:

  • Use a union to share storage with a pointer:
    union U { void* ptr; int value }
  • A pointer to the start of a garbage collected object need not be maintained if a pointer to the interior of the object exists.
    char[] p = new char[10];
char[] q = p[3..6];
// q is enough to hold on to the object, don't need to keep
// p as well.

One can avoid using pointers anyway for most tasks. D provides features rendering most explicit pointer uses obsolete, such as reference objects, dynamic arrays, and garbage collection. Pointers are provided in order to interface successfully with C APIs and for some low level work.

Working with the Garbage Collector

Garbage collection doesn't solve every memory deallocation problem. For example, if a pointer to a large data structure is kept, the garbage collector cannot reclaim it, even if it is never referred to again. To eliminate this problem, it is good practice to set a reference or pointer to an object to null when no longer needed.

This advice applies only to static references or references embedded inside other objects. There is not much point for such stored on the stack to be nulled because new stack frames are initialized anyway.

Object Pinning and a Moving Garbage Collector

Although D does not currently use a moving garbage collector, by following the rules listed above one can be implemented. No special action is required to pin objects. A moving collector will only move objects for which there are no ambiguous references, and for which it can update those references. All other objects will be automatically pinned.

D Operations That Involve the Garbage Collector

Some sections of code may need to avoid using the garbage collector. The following constructs may allocate memory using the garbage collector:

  • NewExpression
  • Array appending
  • Array concatenation
  • Array literals (except when used to initialize static data)
  • Associative array literals
  • Any insertion, removal, or lookups in an associative array
  • Extracting keys or values from an associative array
  • Taking the address of (i.e. making a delegate to) a nested function that accesses variables in an outer scope
  • A function literal that accesses variables in an outer scope
  • An AssertExpression that fails its condition

References

  • Wikipedia
  • GC FAQ
  • Uniprocessor Garbage Collector Techniques
  • Garbage Collection : Algorithms for Automatic Dynamic Memory Management
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Floating Point - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Floating Point

Floating Point Intermediate Values

On many computers, greater precision operations do not take any longer than lesser precision operations, so it makes numerical sense to use the greatest precision available for internal temporaries. The philosophy is not to dumb down the language to the lowest common hardware denominator, but to enable the exploitation of the best capabilities of target hardware.

For floating point operations and expression intermediate values, a greater precision can be used than the type of the expression. Only the minimum precision is set by the types of the operands, not the maximum. Implementation Note: On Intel x86 machines, for example, it is expected (but not required) that the intermediate calculations be done to the full 80 bits of precision implemented by the hardware.

It's possible that, due to greater use of temporaries and common subexpressions, optimized code may produce a more accurate answer than unoptimized code.

Algorithms should be written to work based on the minimum precision of the calculation. They should not degrade or fail if the actual precision is greater. Float or double types, as opposed to the real (extended) type, should only be used for:

  • reducing memory consumption for large arrays
  • when speed is more important than accuracy
  • data and function argument compatibility with C

Floating Point Constant Folding

Regardless of the type of the operands, floating point constant folding is done in real or greater precision. It is always done following IEEE 754 rules and round-to-nearest is used.

Floating point constants are internally represented in the implementation in at least real precision, regardless of the constant's type. The extra precision is available for constant folding. Committing to the precision of the result is done as late as possible in the compilation process. For example:

const float f = 0.2f;
writefln(f - 0.2);

will print 0. A non-const static variable's value cannot be propagated at compile time, so:

static float f = 0.2f;
writefln(f - 0.2);

will print 2.98023e-09. Hex floating point constants can also be used when specific floating point bit patterns are needed that are unaffected by rounding. To find the hex value of 0.2f:

import std.stdio;

void main() {
  writefln("%a", 0.2f);
}

which is 0x1.99999ap-3. Using the hex constant:

const float f = 0x1.99999ap-3f;
writefln(f - 0.2);

prints 2.98023e-09.

Different compiler settings, optimization settings, and inlining settings can affect opportunities for constant folding, therefore the results of floating point calculations may differ depending on those settings.

Rounding Control

IEEE 754 floating point arithmetic includes the ability to set 4 different rounding modes. These are accessible via the functions in std.c.fenv.

If the floating-point rounding mode is changed within a function, it must be restored before the function exits. If this rule is violated (for example, by the use of inline asm), the rounding mode used for subsequent calculations is undefined.

Exception Flags

IEEE 754 floating point arithmetic can set several flags based on what happened with a computation:

FE_INVALID
FE_DENORMAL
FE_DIVBYZERO
FE_OVERFLOW
FE_UNDERFLOW
FE_INEXACT

These flags can be set/reset via the functions in std.c.fenv.

Floating Point Comparisons

In addition to the usual < <= > >= == != comparison operators, D adds more that are specific to floating point. These are !<>= <> <>= !<= !< !>= !> !<> and match the semantics for the NCEG extensions to C. See Floating point comparisons.

Floating Point Transformations

An implementation may perform transformations on floating point computations in order to reduce their strength, i.e. their runtime computation time. Because floating point math does not precisely follow mathematical rules, some transformations are not valid, even though some other programming languages still allow them.

The following transformations of floating point expressions are not allowed because under IEEE rules they could produce different results.

Disallowed Floating Point Transformations
transformation | comments
x + 0 → x | not valid if x is -0
x - 0 → x | not valid if x is ±0 and rounding is towards -∞
-x ↔ 0 - x | not valid if x is +0
x - x → 0 | not valid if x is NaN or ±∞
x - y ↔ -(y - x) | not valid because (1-1=+0) whereas -(1-1)=-0
x * 0 → 0 | not valid if x is NaN or ±∞
x / c ↔ x * (1/c) | valid if (1/c) yields an exact result
x != x → false | not valid if x is a NaN
x == x → true | not valid if x is a NaN
x !op y ↔ !(x op y) | not valid if x or y is a NaN

Of course, transformations that would alter side effects are also invalid.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Inline Assembler - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Inline Assembler

Some Assembly Required

D, being a systems programming language, provides an inline assembler. The inline assembler is standardized for D implementations across the same CPU family, for example, the Intel Pentium inline assembler for a Win32 D compiler will be syntax compatible with the inline assembler for Linux running on an Intel Pentium.

Implementations of D on different architectures, however, are free to innovate upon the memory model, function call/return conventions, argument passing conventions, etc.

This document describes the x86 implementation of the inline assembler.

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

Labels

Assembler instructions can be labeled just like other statements. They can be the target of goto statements. For example:

void *pc;
asm
{
  call L1          ;
 L1:               ;
  pop  EBX         ;
  mov  pc[EBP],EBX ; // pc now points to code at L1
}

align IntegerExpression

IntegerExpression:
    IntegerLiteral
    Identifier

Causes the assembler to emit NOP instructions to align the next assembler instruction on an IntegerExpression boundary. IntegerExpression must evaluate at compile time to an integer that is a power of 2.

Aligning the start of a loop body can sometimes have a dramatic effect on the execution speed.

even

Causes the assembler to emit NOP instructions to align the next assembler instruction on an even boundary.

naked

Causes the compiler to not generate the function prolog and epilog sequences. This means such is the responsibility of inline assembly programmer, and is normally used when the entire function is to be written in assembler.

db, ds, di, dl, df, dd, de

These pseudo ops are for inserting raw data directly into the code. db is for bytes, ds is for 16 bit words, di is for 32 bit words, dl is for 64 bit words, df is for 32 bit floats, dd is for 64 bit doubles, and de is for 80 bit extended reals. Each can have multiple operands. If an operand is a string literal, it is as if there were length operands, where length is the number of characters in the string. One character is used per operand. For example:
asm
{
  db 5,6,0x83;   // insert bytes 0x05, 0x06, and 0x83 into code
  ds 0x1234;     // insert bytes 0x34, 0x12
  di 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00
  dl 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  df 1.234;      // insert float 1.234
  dd 1.234;      // insert double 1.234
  de 1.234;      // insert real 1.234
  db "abc";      // insert bytes 0x61, 0x62, and 0x63
  ds "abc";      // insert bytes 0x61, 0x00, 0x62, 0x00, 0x63, 0x00
}

Opcodes

A list of supported opcodes is at the end.

The following registers are supported. Register names are always in upper case.

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

Special Cases

lock, rep, repe, repne, repnz, repz
These prefix instructions do not appear in the same statement as the instructions they prefix; they appear in their own statement. For example:
asm {
  rep   ;
  movsb ;
}
pause
This opcode is not supported by the assembler, instead use
asm {
  rep  ;
  nop  ;
}
which produces the same result.
floating point ops
Use the two operand form of the instruction format;
fdiv ST(1);	// wrong
fmul ST;        // wrong
fdiv ST,ST(1);	// right
fmul ST,ST(0);	// right

Operands

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

The operand syntax more or less follows the Intel CPU documentation conventions. In particular, the convention is that for two operand instructions the source is the right operand and the destination is the left operand. The syntax differs from that of Intel's in order to be compatible with the D language tokenizer and to simplify parsing.

The seg means load the segment number that the symbol is in. This is not relevant for flat model code. Instead, do a move from the relevant segment register.

Operand Types

AsmTypePrefix:
    near ptr
    far ptr
    byte ptr
    short ptr
    int ptr
    word ptr
    dword ptr
    qword ptr
    float ptr
    double ptr
    real ptr

In cases where the operand size is ambiguous, as in:

add	[EAX],3		;

it can be disambiguated by using an AsmTypePrefix:

add  byte ptr [EAX],3 ;
add  int ptr [EAX],7  ;

far ptr is not relevant for flat model code.

Struct/Union/Class Member Offsets

To access members of an aggregate, given a pointer to the aggregate is in a register, use the qualified name of the member:

struct Foo { int a,b,c; }
int bar(Foo *f) {
  asm {
    mov EBX,f          ;
    mov EAX,Foo.b[EBX] ;
  }
}

Stack Variables

Stack variables (variables local to a function and allocated on the stack) are accessed via the name of the variable indexed by EBP:

int foo(int x) {
  asm {
    mov EAX,x[EBP] ; // loads value of parameter x into EAX
    mov EAX,x      ; // does the same thing
  }
}

If the [EBP] is omitted, it is assumed for local variables. If naked is used, this no longer holds.

Special Symbols

$
Represents the program counter of the start of the next instruction. So,
jmp  $  ;
branches to the instruction following the jmp instruction. The $ can only appear as the target of a jmp or call instruction.
__LOCAL_SIZE
This gets replaced by the number of local bytes in the local stack frame. It is most handy when the naked is invoked and a custom stack frame is programmed.

Opcodes Supported

aaa | aad | aam | aas | adc
add | addpd | addps | addsd | addss
and | andnpd | andnps | andpd | andps
arpl | bound | bsf | bsr | bswap
bt | btc | btr | bts | call
cbw | cdq | clc | cld | clflush
cli | clts | cmc | cmova | cmovae
cmovb | cmovbe | cmovc | cmove | cmovg
cmovge | cmovl | cmovle | cmovna | cmovnae
cmovnb | cmovnbe | cmovnc | cmovne | cmovng
cmovnge | cmovnl | cmovnle | cmovno | cmovnp
cmovns | cmovnz | cmovo | cmovp | cmovpe
cmovpo | cmovs | cmovz | cmp | cmppd
cmpps | cmps | cmpsb | cmpsd | cmpss
cmpsw | cmpxch8b | cmpxchg | comisd | comiss
cpuid | cvtdq2pd | cvtdq2ps | cvtpd2dq | cvtpd2pi
cvtpd2ps | cvtpi2pd | cvtpi2ps | cvtps2dq | cvtps2pd
cvtps2pi | cvtsd2si | cvtsd2ss | cvtsi2sd | cvtsi2ss
cvtss2sd | cvtss2si | cvttpd2dq | cvttpd2pi | cvttps2dq
cvttps2pi | cvttsd2si | cvttss2si | cwd | cwde
da | daa | das | db | dd
de | dec | df | di | div
divpd | divps | divsd | divss | dl
dq | ds | dt | dw | emms
enter | f2xm1 | fabs | fadd | faddp
fbld | fbstp | fchs | fclex | fcmovb
fcmovbe | fcmove | fcmovnb | fcmovnbe | fcmovne
fcmovnu | fcmovu | fcom | fcomi | fcomip
fcomp | fcompp | fcos | fdecstp | fdisi
fdiv | fdivp | fdivr | fdivrp | feni
ffree | fiadd | ficom | ficomp | fidiv
fidivr | fild | fimul | fincstp | finit
fist | fistp | fisub | fisubr | fld
fld1 | fldcw | fldenv | fldl2e | fldl2t
fldlg2 | fldln2 | fldpi | fldz | fmul
fmulp | fnclex | fndisi | fneni | fninit
fnop | fnsave | fnstcw | fnstenv | fnstsw
fpatan | fprem | fprem1 | fptan | frndint
frstor | fsave | fscale | fsetpm | fsin
fsincos | fsqrt | fst | fstcw | fstenv
fstp | fstsw | fsub | fsubp | fsubr
fsubrp | ftst | fucom | fucomi | fucomip
fucomp | fucompp | fwait | fxam | fxch
fxrstor | fxsave | fxtract | fyl2x | fyl2xp1
hlt | idiv | imul | in | inc
ins | insb | insd | insw | int
into | invd | invlpg | iret | iretd
ja | jae | jb | jbe | jc
jcxz | je | jecxz | jg | jge
jl | jle | jmp | jna | jnae
jnb | jnbe | jnc | jne | jng
jnge | jnl | jnle | jno | jnp
jns | jnz | jo | jp | jpe
jpo | js | jz | lahf | lar
ldmxcsr | lds | lea | leave | les
lfence | lfs | lgdt | lgs | lidt
lldt | lmsw | lock | lods | lodsb
lodsd | lodsw | loop | loope | loopne
loopnz | loopz | lsl | lss | ltr
maskmovdqu | maskmovq | maxpd | maxps | maxsd
maxss | mfence | minpd | minps | minsd
minss | mov | movapd | movaps | movd
movdq2q | movdqa | movdqu | movhlps | movhpd
movhps | movlhps | movlpd | movlps | movmskpd
movmskps | movntdq | movnti | movntpd | movntps
movntq | movq | movq2dq | movs | movsb
movsd | movss | movsw | movsx | movupd
movups | movzx | mul | mulpd | mulps
mulsd | mulss | neg | nop | not
or | orpd | orps | out | outs
outsb | outsd | outsw | packssdw | packsswb
packuswb | paddb | paddd | paddq | paddsb
paddsw | paddusb | paddusw | paddw | pand
pandn | pavgb | pavgw | pcmpeqb | pcmpeqd
pcmpeqw | pcmpgtb | pcmpgtd | pcmpgtw | pextrw
pinsrw | pmaddwd | pmaxsw | pmaxub | pminsw
pminub | pmovmskb | pmulhuw | pmulhw | pmullw
pmuludq | pop | popa | popad | popf
popfd | por | prefetchnta | prefetcht0 | prefetcht1
prefetcht2 | psadbw | pshufd | pshufhw | pshuflw
pshufw | pslld | pslldq | psllq | psllw
psrad | psraw | psrld | psrldq | psrlq
psrlw | psubb | psubd | psubq | psubsb
psubsw | psubusb | psubusw | psubw | punpckhbw
punpckhdq | punpckhqdq | punpckhwd | punpcklbw | punpckldq
punpcklqdq | punpcklwd | push | pusha | pushad
pushf | pushfd | pxor | rcl | rcpps
rcpss | rcr | rdmsr | rdpmc | rdtsc
rep | repe | repne | repnz | repz
ret | retf | rol | ror | rsm
rsqrtps | rsqrtss | sahf | sal | sar
sbb | scas | scasb | scasd | scasw
seta | setae | setb | setbe | setc
sete | setg | setge | setl | setle
setna | setnae | setnb | setnbe | setnc
setne | setng | setnge | setnl | setnle
setno | setnp | setns | setnz | seto
setp | setpe | setpo | sets | setz
sfence | sgdt | shl | shld | shr
shrd | shufpd | shufps | sidt | sldt
smsw | sqrtpd | sqrtps | sqrtsd | sqrtss
stc | std | sti | stmxcsr | stos
stosb | stosd | stosw | str | sub
subpd | subps | subsd | subss | sysenter
sysexit | test | ucomisd | ucomiss | ud2
unpckhpd | unpckhps | unpcklpd | unpcklps | verr
verw | wait | wbinvd | wrmsr | xadd
xchg | xlat | xlatb | xor | xorpd
xorps |  |  |  |

Pentium 4 (Prescott) Opcodes Supported

addsubpd | addsubps | fisttp | haddpd | haddps
hsubpd | hsubps | lddqu | monitor | movddup
movshdup | movsldup | mwait |  |

AMD Opcodes Supported

pavgusb | pf2id | pfacc | pfadd | pfcmpeq
pfcmpge | pfcmpgt | pfmax | pfmin | pfmul
pfnacc | pfpnacc | pfrcp | pfrcpit1 | pfrcpit2
pfrsqit1 | pfrsqrt | pfsub | pfsubr | pi2fd
pmulhrw | pswapd
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Documentation Generator - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Documentation Generator

The D programming language enables embedding both contracts and test code along side the actual code, which helps to keep them all consistent with each other. One thing lacking is the documentation, as ordinary comments are usually unsuitable for automated extraction and formatting into manual pages. Embedding the user documentation into the source code has important advantages, such as not having to write the documentation twice, and the likelihood of the documentation staying consistent with the code.

Some existing approaches to this are:

  • Doxygen which already has some support for D
  • Java's Javadoc, probably the most well-known
  • C#'s embedded XML
  • Other documentation tools

D's goals for embedded documentation are:

  1. It looks good as embedded documentation, not just after it is extracted and processed.
  2. It's easy and natural to write, i.e. minimal reliance on <tags> and other clumsy forms one would never see in a finished document.
  3. It does not repeat information that the compiler already knows from parsing the code.
  4. It doesn't rely on embedded HTML, as such will impede extraction and formatting for other purposes.
  5. It's based on existing D comment forms, so it is completely independent of parsers only interested in D code.
  6. It should look and feel different from code, so it won't be visually confused with code.
  7. It should be possible for the user to use Doxygen or other documentation extractor if desired.

Specification

The specification for the form of embedded documentation comments only specifies how information is to be presented to the compiler. It is implementation-defined how that information is used and the form of the final presentation. Whether the final presentation form is an HTML web page, a man page, a PDF file, etc. is not specified as part of the D Programming Language.

Phases of Processing

Embedded documentation comments are processed in a series of phases:

  1. Lexical - documentation comments are identified and attached to tokens.
  2. Parsing - documentation comments are associated with specific declarations and combined.
  3. Sections - each documentation comment is divided up into a sequence of sections.
  4. Special sections are processed.
  5. Highlighting of non-special sections is done.
  6. All sections for the module are combined.
  7. Macro text substitution is performed to produce the final result.

Lexical

Embedded documentation comments are one of the following forms:

  1. /** ... */ The two *'s after the opening /
  2. /++ ... +/ The two +'s after the opening /
  3. /// The three slashes

The following are all embedded documentation comments:

/// This is a one line documentation comment.

/** So is this. */

/++ And this. +/

/**
   This is a brief documentation comment.
 */

/**
 * The leading * on this line is not part of the documentation comment.
 */

/*********************************
   The extra *'s immediately following the /** are not
   part of the documentation comment.
 */

/++
   This is a brief documentation comment.
 +/

/++
 + The leading + on this line is not part of the documentation comment.
 +/

/+++++++++++++++++++++++++++++++++
   The extra +'s immediately following the / ++ are not
   part of the documentation comment.
 +/

/**************** Closing *'s are not part *****************/

The extra *'s and +'s on the comment opening, closing and left margin are ignored and are not part of the embedded documentation. Comments not following one of those forms are not documentation comments.

Parsing

Each documentation comment is associated with a declaration. If the documentation comment is on a line by itself or with only whitespace to the left, it refers to the next declaration. Multiple documentation comments applying to the same declaration are concatenated. Documentation comments not associated with a declaration are ignored. Documentation comments preceding the ModuleDeclaration apply to the entire module. If the documentation comment appears on the same line to the right of a declaration, it applies to that.

If a documentation comment for a declaration consists only of the identifier ditto then the documentation comment for the previous declaration at the same declaration scope is applied to this declaration as well.

If there is no documentation comment for a declaration, that declaration may not appear in the output. To ensure it does appear in the output, put an empty declaration comment for it.

int a;  /// documentation for a; b has no documentation
int b;

/** documentation for c and d */
/** more documentation for c and d */
int c;
/** ditto */
int d;

/** documentation for e and f */ int e;
int f;	/// ditto

/** documentation for g */
int g; /// more documentation for g

/// documentation for C and D
class C {
  int x; /// documentation for C.x

  /** documentation for C.y and C.z */
  int y;
  int z; /// ditto
}

/// ditto
class D { }

Sections

The document comment is a series of Sections. A Section is a name that is the first non-blank character on a line immediately followed by a ':'. This name forms the section name. The section name is not case sensitive.

Summary

The first section is the Summary, and does not have a section name. It is first paragraph, up to a blank line or a section name. While the summary can be any length, try to keep it to one line. The Summary section is optional.

Description

The next unnamed section is the Description. It consists of all the paragraphs following the Summary until a section name is encountered or the end of the comment.

While the Description section is optional, there cannot be a Description without a Summary section.

/***********************************
 * Brief summary of what
 * myfunc does, forming the summary section.
 *
 * First paragraph of synopsis description.
 *
 * Second paragraph of
 * synopsis description.
 */

void myfunc() { }

Named sections follow the Summary and Description unnamed sections.

Standard Sections

For consistency and predictability, there are several standard sections. None of these are required to be present.

Authors:
Lists the author(s) of the declaration.
/**
 * Authors: Melvin D. Nerd, melvin@mailinator.com
 */
Bugs:
Lists any known bugs.
/**
 * Bugs: Doesn't work for negative values.
 */
Date:
Specifies the date of the current revision. The date should be in a form parseable by std.date.
/**
 * Date: March 14, 2003
 */
Deprecated:
Provides an explanation for and corrective action to take if the associated declaration is marked as deprecated.
/**
 * Deprecated: superseded by function bar().
 */

deprecated void foo() { ... }
Examples:
Any usage examples
/**
 * Examples:
 * --------------------
 * writefln("3"); // writes '3' to stdout
 * --------------------
 */
History:
Revision history.
/**
 * History:
 *	V1 is initial version
 *
 *	V2 added feature X
 */
License:
Any license information for copyrighted code.
/**
 * License: use freely for any purpose
 */

void bar() { ... }
Returns:
Explains the return value of the function. If the function returns void, don't redundantly document it.
/**
 * Read the file.
 * Returns: The contents of the file.
 */

void[] readFile(char[] filename) { ... }
See_Also:
List of other symbols and URL's to related items.
/**
 * See_Also:
 *    foo, bar, http://www.digitalmars.com/d/phobos/index.html
 */
Standards:
If this declaration is compliant with any particular standard, the description of it goes here.
/**
 * Standards: Conforms to DSPEC-1234
 */
Throws:
Lists exceptions thrown and under what circumstances they are thrown.
/**
 * Write the file.
 * Throws: WriteException on failure.
 */

void writeFile(char[] filename) { ... }
Version:
Specifies the current version of the declaration.
/**
 * Version: 1.6a
 */

Special Sections

Some sections have specialized meanings and syntax.

Copyright:
This contains the copyright notice. The macro COPYRIGHT is set to the contents of the section when it documents the module declaration. The copyright section only gets this special treatment when it is for the module declaration.
/** Copyright: Public Domain */

module foo;
Params:
Function parameters can be documented by listing them in a params section. Each line that starts with an identifier followed by an '=' starts a new parameter description. A description can span multiple lines.
/***********************************
 * foo does this.
 * Params:
 *	x =	is for this
 *		and not for that
 *	y =	is for that
 */

void foo(int x, int y)
{
}
Macros:
The macros section follows the same syntax as the Params: section. It's a series of NAME=value pairs. The NAME is the macro name, and value is the replacement text.
/**
 * Macros:
 *	FOO =	now is the time for
 *		all good men
 *	BAR =	bar
 *	MAGENTA =   &lt;font color=magenta&gt;&lt;/font&gt;
 */

Highlighting

Embedded Comments

The documentation comments can themselves be commented using the $(DDOC_COMMENT comment text) syntax. These comments do not nest.

Embedded Code

D code can be embedded using lines beginning with at least three hyphens (ignoring whitespace) to delineate the code section:

/++
 + Our function.
 +
 + Example:
 + ---
 + import std.stdio;
 +
 + void foo()
 + {
 +     writefln("foo!");  /* print the string */
 + }
 + ---
 +/

Note that the documentation comment uses the /++ ... +/ form so that /* ... */ can be used inside the code section.

Embedded HTML

HTML can be embedded into the documentation comments, and it will be passed through to the HTML output unchanged. However, since it is not necessarily true that HTML will be the desired output format of the embedded documentation comment extractor, it is best to avoid using it where practical.

/**
 * Example of embedded HTML:
 *
 * <ol>
 *   <li><a href="http://www.digitalmars.com">Digital Mars</a></li>
 *   <li><a href="http://www.classicempire.com">Empire</a></li>
 * </ol>
 */

Emphasis

Identifiers in documentation comments that are function parameters or are names that are in scope at the associated declaration are emphasized in the output. This emphasis can take the form of italics, boldface, a hyperlink, etc. How it is emphasized depends on what it is - a function parameter, type, D keyword, etc. To prevent unintended emphasis of an identifier, it can be preceded by an underscore (_). The underscore will be stripped from the output.

Character Entities

Some characters have special meaning to the documentation processor, to avoid confusion it can be best to replace them with their corresponding character entities:

Characters and Entities
Character | Entity
< | &lt;
> | &gt;
& | &amp;

It is not necessary to do this inside a code section, or if the special character is not immediately followed by a # or a letter.

No Documentation

No documentation is generated for the following constructs, even if they have a documentation comment:

  • Invariants
  • Postblits
  • Destructors
  • Static constructors and static destructors
  • Class info, type info, and module info

Macros

The documentation comment processor includes a simple macro text preprocessor. When a $(NAME) appears in section text it is replaced with NAME's corresponding replacement text. The replacement text is then recursively scanned for more macros. If a macro is recursively encountered, with no argument or with the same argument text as the enclosing macro, it is replaced with no text. Macro invocations that cut across replacement text boundaries are not expanded. If the macro name is undefined, the replacement text has no characters in it. If a $(NAME) is desired to exist in the output without being macro expanded, the $ should be replaced with &#36;.

Macros can have arguments. Any text from the end of the identifier to the closing ‘)’ is the $0 argument. A $0 in the replacement text is replaced with the argument text. If there are commas in the argument text, $1 will represent the argument text up to the first comma, $2 from the first comma to the second comma, etc., up to $9. $+ represents the text from the first comma to the closing ‘)’. The argument text can contain nested parentheses, "" or '' strings, comments, or tags. If stray, unnested parentheses are used, they can be replaced with the entity &#40; for ( and &#41; for ).

Macro definitions come from the following sources, in the specified order:

  1. Predefined macros.
  2. Definitions from file specified by sc.ini's or dmd.conf DDOCFILE setting.
  3. Definitions from *.ddoc files specified on the command line.
  4. Runtime definitions generated by Ddoc.
  5. Definitions from any Macros: sections.

Macro redefinitions replace previous definitions of the same name. This means that the sequence of macro definitions from the various sources forms a hierarchy.

Macro names beginning with "D_" and "DDOC_" are reserved.

Predefined Macros

These are hardwired into Ddoc, and represent the minimal definitions needed by Ddoc to format and highlight the presentation. The definitions are for simple HTML.

B =     <b>$0</b>
I =     <i>$0</i>
U =     <u>$0</u>
P =     <p>$0</p>
DL =    <dl>$0</dl>
DT =    <dt>$0</dt>
DD =    <dd>$0</dd>
TABLE = <table>$0</table>
TR =    <tr>$0</tr>
TH =    <th>$0</th>
TD =    <td>$0</td>
OL =    <ol>$0</ol>
UL =    <ul>$0</ul>
LI =    <li>$0</li>
BIG =   <big>$0</big>
SMALL = <small>$0</small>
BR =    <br>
LINK =  <a href="$0">$0</a>
LINK2 = <a href="$1">$+</a>
LPAREN= (
RPAREN= )

RED =   <font color=red>$0</font>
BLUE =  <font color=blue>$0</font>
GREEN = <font color=green>$0</font>
YELLOW =<font color=yellow>$0</font>
BLACK = <font color=black>$0</font>
WHITE = <font color=white>$0</font>

D_CODE = <pre class="d_code">$0</pre>
D_COMMENT = $(GREEN $0)
D_STRING  = $(RED $0)
D_KEYWORD = $(BLUE $0)
D_PSYMBOL = $(U $0)
D_PARAM   = $(I $0)

DDOC = <html><head>
       <META http-equiv="content-type" content="text/html; charset=utf-8">
       <title>$(TITLE)</title>
       </head><body>
       <h1>$(TITLE)</h1>
       $(BODY)
       </body></html>

DDOC_COMMENT   = <!-- $0 -->
DDOC_DECL      = $(DT $(BIG $0))
DDOC_DECL_DD   = $(DD $0)
DDOC_DITTO     = $(BR)$0
DDOC_SECTIONS  = $0
DDOC_SUMMARY   = $0$(BR)$(BR)
DDOC_DESCRIPTION = $0$(BR)$(BR)
DDOC_AUTHORS   = $(B Authors:)$(BR)
        $0$(BR)$(BR)
DDOC_BUGS      = $(RED BUGS:)$(BR)
        $0$(BR)$(BR)
DDOC_COPYRIGHT = $(B Copyright:)$(BR)
        $0$(BR)$(BR)
DDOC_DATE      = $(B Date:)$(BR)
        $0$(BR)$(BR)
DDOC_DEPRECATED = $(RED Deprecated:)$(BR)
        $0$(BR)$(BR)
DDOC_EXAMPLES  = $(B Examples:)$(BR)
        $0$(BR)$(BR)
DDOC_HISTORY   = $(B History:)$(BR)
        $0$(BR)$(BR)
DDOC_LICENSE   = $(B License:)$(BR)
        $0$(BR)$(BR)
DDOC_RETURNS   = $(B Returns:)$(BR)
        $0$(BR)$(BR)
DDOC_SEE_ALSO  = $(B See Also:)$(BR)
        $0$(BR)$(BR)
DDOC_STANDARDS = $(B Standards:)$(BR)
        $0$(BR)$(BR)
DDOC_THROWS    = $(B Throws:)$(BR)
        $0$(BR)$(BR)
DDOC_VERSION   = $(B Version:)$(BR)
        $0$(BR)$(BR)
DDOC_SECTION_H = $(B $0)$(BR)$(BR)
DDOC_SECTION   = $0$(BR)$(BR)
DDOC_MEMBERS   = $(DL $0)
DDOC_MODULE_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_CLASS_MEMBERS    = $(DDOC_MEMBERS $0)
DDOC_STRUCT_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_ENUM_MEMBERS     = $(DDOC_MEMBERS $0)
DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)
DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)
DDOC_PARAM_ROW = $(TR $0)
DDOC_PARAM_ID  = $(TD $0)
DDOC_PARAM_DESC  = $(TD $0)
DDOC_BLANKLINE = $(BR)$(BR)

DDOC_ANCHOR  = <a name="$1"></a>
DDOC_PSYMBOL = $(U $0)
DDOC_KEYWORD = $(B $0)
DDOC_PARAM   = $(I $0)

Ddoc does not generate HTML code. It formats into the basic formatting macros, which (in their predefined form) are then expanded into HTML. If output other than HTML is desired, then these macros need to be redefined.

Basic Formatting Macros
B | boldface the argument
I | italicize the argument
U | underline the argument
P | argument is a paragraph
DL | argument is a definition list
DT | argument is a definition in a definition list
DD | argument is a description of a definition
TABLE | argument is a table
TR | argument is a row in a table
TH | argument is a header entry in a row
TD | argument is a data entry in a row
OL | argument is an ordered list
UL | argument is an unordered list
LI | argument is an item in a list
BIG | argument is one font size bigger
SMALL | argument is one font size smaller
BR | start new line
LINK | generate clickable link on argument
LINK2 | generate clickable link, first arg is address
RED | argument is set to be red
BLUE | argument is set to be blue
GREEN | argument is set to be green
YELLOW | argument is set to be yellow
BLACK | argument is set to be black
WHITE | argument is set to be white
D_CODE | argument is D code
DDOC | overall template for output

DDOC is special in that it specifies the boilerplate into which the entire generated text is inserted (represented by the Ddoc generated macro BODY). For example, in order to use a style sheet, DDOC would be redefined as:

DDOC =	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html><head>
    <META http-equiv="content-type" content="text/html; charset=utf-8">
    <title>$(TITLE)</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    </head><body>
    <h1>$(TITLE)</h1>
    $(BODY)
    </body></html>

DDOC_COMMENT is used to insert comments into the output file.

Highlighting of D code is performed by the following macros:

D Code Formatting Macros
D_COMMENT | Highlighting of comments
D_STRING | Highlighting of string literals
D_KEYWORD | Highlighting of D keywords
D_PSYMBOL | Highlighting of current declaration name
D_PARAM | Highlighting of current function declaration parameters

The highlighting macros start with DDOC_. They control the formatting of individual parts of the presentation.

Ddoc Section Formatting Macros
DDOC_DECL | Highlighting of the declaration.
DDOC_DECL_DD | Highlighting of the description of a declaration.
DDOC_DITTO | Highlighting of ditto declarations.
DDOC_SECTIONS | Highlighting of all the sections.
DDOC_SUMMARY | Highlighting of the summary section.
DDOC_DESCRIPTION | Highlighting of the description section.
DDOC_AUTHORS .. DDOC_VERSION | Highlighting of the corresponding standard section.
DDOC_SECTION_H | Highlighting of the section name of a non-standard section.
DDOC_SECTION | Highlighting of the contents of a non-standard section.
DDOC_MEMBERS | Default highlighting of all the members of a class, struct, etc.
DDOC_MODULE_MEMBERS | Highlighting of all the members of a module.
DDOC_CLASS_MEMBERS | Highlighting of all the members of a class.
DDOC_STRUCT_MEMBERS | Highlighting of all the members of a struct.
DDOC_ENUM_MEMBERS | Highlighting of all the members of an enum.
DDOC_TEMPLATE_MEMBERS | Highlighting of all the members of a template.
DDOC_PARAMS | Highlighting of a function parameter section.
DDOC_PARAM_ROW | Highlighting of a name=value function parameter.
DDOC_PARAM_ID | Highlighting of the parameter name.
DDOC_PARAM_DESC | Highlighting of the parameter value.
DDOC_ANCHOR | Expands to a named anchor used for hyperlinking to a particular declaration section. Argument $1 expands to the qualified declaration name.
DDOC_PSYMBOL | Highlighting of declaration name to which a particular section is referring.
DDOC_KEYWORD | Highlighting of D keywords.
DDOC_PARAM | Highlighting of function parameters.
DDOC_BLANKLINE | Inserts a blank line.

For example, one could redefine DDOC_SUMMARY:

DDOC_SUMMARY = $(GREEN $0)

And all the summary sections will now be green.

Macro Definitions from sc.ini's DDOCFILE

A text file of macro definitions can be created, and specified in sc.ini:

DDOCFILE=myproject.ddoc

Macro Definitions from .ddoc Files on the Command Line

File names on the DMD command line with the extension .ddoc are text files that are read and processed in order.

Macro Definitions Generated by Ddoc

Generated Macro Definitions
Macro Name | Contents
BODY | Set to the generated document text.
TITLE | Set to the module name.
DATETIME | Set to the current date and time.
YEAR | Set to the current year.
COPYRIGHT | Set to the contents of any Copyright: section that is part of the module comment.
DOCFILENAME | Set to the name of the generated output file.
SRCFILENAME | Set to the name of the source file the documentation is being generated from.

Using Ddoc for other Documentation

Ddoc is primarily designed for use in producing documentation from embedded comments. It can also, however, be used for processing other general documentation. The reason for doing this would be to take advantage of the macro capability of Ddoc and the D code syntax highlighting capability.

If the .d source file starts with the string "Ddoc" then it is treated as general purpose documentation, not as a D code source file. From immediately after the "Ddoc" string to the end of the file or any "Macros:" section forms the document. No automatic highlighting is done to that text, other than highlighting of D code embedded between lines delineated with --- lines. Only macro processing is done.

Much of the D documentation itself is generated this way, including this page. Such documentation is marked at the bottom as being generated by Ddoc.

References

CandyDoc is a very nice example of how one can customize the Ddoc results with macros and style sheets.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Interfacing to C - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Interfacing to C

D is designed to fit comfortably with a C compiler for the target system. D makes up for not having its own VM by relying on the target environment's C runtime library. It would be senseless to attempt to port to D or write D wrappers for the vast array of C APIs available. How much easier it is to just call them directly.

This is done by matching the C compiler's data types, layouts, and function call/return sequences.

Calling C Functions

C functions can be called directly from D. There is no need for wrapper functions, argument swizzling, and the C functions do not need to be put into a separate DLL.

The C function must be declared and given a calling convention, most likely the "C" calling convention, for example:

extern (C) int strcmp(char* string1, char* string2);

and then it can be called within D code in the obvious way:

import std.string;
int myDfunction(char[] s) {
  return strcmp(std.string.toStringz(s), "foo");
}

There are several things going on here:

  • D understands how C function names are "mangled" and the correct C function call/return sequence.
  • C functions cannot be overloaded with another C function with the same name.
  • There are no __cdecl, __far, __stdcall, __declspec, or other such C extended type modifiers in D. These are handled by linkage attributes, such as extern (C).
  • There is no volatile type modifier in D. To declare a C function that uses volatile, just drop the keyword from the declaration.
  • Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated.

C code can correspondingly call D functions, if the D functions use an attribute that is compatible with the C compiler, most likely the extern (C):

// myfunc() can be called from any C function
extern (C) {
  void myfunc(int a, int b) {
    ...
  }
}

Storage Allocation

C code explicitly manages memory with calls to malloc() and free(). D allocates memory using the D garbage collector, so no explicit free's are necessary.

D can still explicitly allocate memory using std.c.stdlib.malloc() and std.c.stdlib.free(), these are useful for connecting to C functions that expect malloc'd buffers, etc.

If pointers to D garbage collector allocated memory are passed to C functions, it's critical to ensure that that memory will not be collected by the garbage collector before the C function is done with it. This is accomplished by:

  • Making a copy of the data using std.c.stdlib.malloc() and passing the copy instead.
  • Leaving a pointer to it on the stack (as a parameter or automatic variable), as the garbage collector will scan the stack.
  • Leaving a pointer to it in the static data segment, as the garbage collector will scan the static data segment.
  • Registering the pointer with the garbage collector with the std.gc.addRoot() or std.gc.addRange() calls.

An interior pointer to the allocated memory block is sufficient to let the GC know the object is in use; i.e. it is not necessary to maintain a pointer to the beginning of the allocated memory.

The garbage collector does not scan the stacks of threads not created by the D Thread interface. Nor does it scan the data segments of other DLL's, etc.

Data Type Compatibility

D And C Type Equivalence
D | C
 | 32 bit | 64 bit
void | void
byte | signed char
ubyte | unsigned char
char | char (chars are unsigned in D)
wchar | wchar_t (when sizeof(wchar_t) is 2)
dchar | wchar_t (when sizeof(wchar_t) is 4)
short | short
ushort | unsigned short
int | int
uint | unsigned
c_long (in core.stdc.config) | long | long
c_ulong (in core.stdc.config) | unsigned long | unsigned long
long | long long | long (or long long)
ulong | unsigned long long | unsigned long (or unsigned long long)
float | float
double | double
real | long double
struct | struct
union | union
enum | enum
class | no equivalent
type* | type *
type[dim] | type[dim]
type[dim]* | type(*)[dim]
type[] | no equivalent
type[type] | no equivalent
type function(parameters) | type(*)(parameters)
type delegate(parameters) | no equivalent
size_t | size_t
ptrdiff_t | ptrdiff_t

These equivalents hold for most C compilers. The C standard does not pin down the sizes of the types, so some care is needed.

Passing D Array Arguments to C Functions

In C, arrays are passed to functions as pointers even if the function prototype says its an array. In D, static arrays are passed by value, not by reference. Thus, the function prototype must be adjusted to match what C expects.

D And C Function Prototype Equivalence
D type | C type
T* | T[]
ref T[dim] | T[dim]

For example:

void foo(int a[3]) { ... } // C code

extern (C)
{
  void foo(ref int[3] a); // D prototype
}

Calling printf()

This mostly means checking that the printf format specifier matches the corresponding D data type. Although printf is designed to handle 0 terminated strings, not D dynamic arrays of chars, it turns out that since D dynamic arrays are a length followed by a pointer to the data, the %.*s format works:

void foo(char[] string) {
  printf("my string is: %.*s\n", string.length, string.ptr);
}

The printf format string literal in the example doesn't end with '\0'. This is because string literals, when they are not part of an initializer to a larger data structure, have a '\0' character helpfully stored after the end of them.

An improved D function for formatted output is std.stdio.writef().

Structs and Unions

D structs and unions are analogous to C's.

C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific #pragma's. D supports explicit alignment attributes that correspond to the C compiler's rules. Check what alignment the C code is using, and explicitly set it for the D struct declaration.

D does not support bit fields. If needed, they can be emulated with shift and mask operations, or use the std.bitmanip.bitfields library type. htod will convert bit fields to inline functions that do the right shift and masks.

D does not support declaring variables of anonymous struct types. In such a case you can define a named struct in D and make it private:

union Info  // C code
{
    struct
    {
        char *name;
    } file;
};

union Info  // D code
{
    private struct File
    {
        char* name;
    }
    File file;
}

Callbacks

D can easily call C callbacks (function pointers), and C can call callbacks provided by D code if the callback is an extern(C) function, or some other linkage that both sides have agreed to (e.g. extern(Windows)).

Here's an example of C code providing a callback to D code:

void someFunc(void *arg) { printf("Called someFunc!\n"); }  // C code
typedef void (*Callback)(void *);
extern "C" Callback getCallback(void)
{
    return someFunc;
}

alias extern(C) int function(int, int) Callback;  // D code
extern(C) Callback getCallback();
void main()
{
    Callback cb = getallback();
    cb();  // invokes the callback
}

And an example of D code providing a callback to C code:

extern "C" void printer(int (*callback)(int, int))  // C code
{
    printf("calling callback with 2 and 4 returns: %d\n", callback(2, 4));
}

alias extern(C) int function(int, int) Callback;  // D code
extern(C) void printer(Callback callback);
extern(C) int sum(int x, int y) { return x + y; }
void main()
{
    printer(&sum);
}

For more info about callbacks read the closures section.

Using Existing C Libraries

Since D can call C code directly, it can also call any C library functions, giving D access to the smorgasbord of existing C libraries. To do so, however, one needs to write a D interface (.di) file, which is a translation of the C .h header file for the C library into D.

For popular C libraries, the first place to look for the corresponding D interface file is the Deimos Project. If it isn't there already, and you write one, please contribute it to the Deimos Project.

Accessing C Globals

C globals can be accessed directly from D. C globals have the C naming convention, and so must be in an extern (C) block. Use the extern storage class to indicate that the global is allocated in the C code, not the D code. C globals default to being in global, not thread local, storage. To reference global storage from D, use the __gshared storage class.

extern (C) extern __gshared int x;
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Interfacing to C++ - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Interfacing to C++

While D is fully capable of interfacing to C, its ability to interface to C++ is much more limited. There are three ways to do it:

  1. Use C++'s ability to create a C interface, and then use D's ability to interface with C to access that interface.
  2. Use C++'s ability to create a COM interface, and then use D's ability to interface with COM to access that interface.
  3. Use the limited ability described here to connect directly to C++ functions and classes.

The General Idea

Being 100% compatible with C++ means more or less adding a fully functional C++ compiler front end to D. Anecdotal evidence suggests that writing such is a minimum of a 10 man-year project, essentially making a D compiler with such capability unimplementable. Other languages looking to hook up to C++ face the same problem, and the solutions have been:

  1. Support the COM interface (but that only works for Windows).
  2. Laboriously construct a C wrapper around the C++ code.
  3. Use an automated tool such as SWIG to construct a C wrapper.
  4. Reimplement the C++ code in the other language.
  5. Give up.

D takes a pragmatic approach that assumes a couple modest accommodations can solve a significant chunk of the problem:

  • matching C++ name mangling conventions
  • matching C++ function calling conventions
  • matching C++ virtual function table layout for single inheritance

Calling C++ Global Functions From D

Given a C++ function in a C++ source file:

#include <iostream>

using namespace std;

int foo(int i, int j, int k) {
  cout << "i = " << i << endl;
  cout << "j = " << j << endl;
  cout << "k = " << k << endl;

  return 7;
}

In the corresponding D code, foo is declared as having C++ linkage and function calling conventions:

extern (C++) int foo(int i, int j, int k);

and then it can be called within the D code:

extern (C++) int foo(int i, int j, int k);

void main() {
  foo(1,2,3);
}

Compiling the two files, the first with a C++ compiler, the second with a D compiler, linking them together, and then running it yields:

i = 1
j = 2
k = 3

There are several things going on here:

  • D understands how C++ function names are "mangled" and the correct C++ function call/return sequence.
  • Because modules are not part of C++, each function with C++ linkage must be globally unique within the program.
  • There are no __cdecl, __far, __stdcall, __declspec, or other such nonstandard C++ extensions in D.
  • There are no volatile type modifiers in D.
  • Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated.

C++ functions that reside in namespaces cannot be direcly called from D.

Calling Global D Functions From C++

To make a D function accessible from C++, give it C++ linkage:

import std.stdio;

extern (C++) int foo(int i, int j, int k) {
  writefln("i = %s", i);
  writefln("j = %s", j);
  writefln("k = %s", k);
  return 1;
}

extern (C++) void bar();

void main() {
  bar();
}

The C++ end looks like:

int foo(int i, int j, int k);

void bar() {
  foo(6, 7, 8);
}

Compiling, linking, and running produces the output:

i = 6
j = 7
k = 8

Classes

D classes are singly rooted by Object, and have an incompatible layout from C++ classes. D interfaces, however, are very similar to C++ single inheritance class heirarchies. So, a D interface with the attribute of extern (C++) will have a virtual function pointer table (vtbl[]) that exactly matches C++'s. A regular D interface has a vtbl[] that differs in that the first entry in the vtbl[] is a pointer to D's RTTI info, whereas in C++ the first entry points to the first virtual function.

Calling C++ Virtual Functions From D

Given C++ source code defining a class like:

#include <iostream>

using namespace std;

class D {
 public:
  virtual int bar(int i, int j, int k)
  {
    cout << "i = " << i << endl;
    cout << "j = " << j << endl;
    cout << "k = " << k << endl;
    return 8;
  }
};

D *getD() {
  D *d = new D();
  return d;
}

We can get at it from D code like:

extern (C++) {
  interface D {
    int bar(int i, int j, int k);
  }

  D getD();
}

void main() {
  D d = getD();
  d.bar(9,10,11);
}

Calling D Virtual Functions From C++

Given D code like:

extern (C++) int callE(E);

extern (C++) interface E {
  int bar(int i, int j, int k);
}

class F : E {
  extern (C++) int bar(int i, int j, int k)
  {
    writefln("i = ", i);
    writefln("j = ", j);
    writefln("k = ", k);
    return 8;
  }
}

void main() {
  F f = new F();
  callE(f);
}

The C++ code to access it looks like:

class E {
 public:
  virtual int bar(int i, int j, int k);
};

int callE(E *e) {
  return e->bar(11,12,13);
}

Note:

  • non-virtual functions, and static member functions, cannot be accessed.
  • class fields can only be accessed via virtual getter and setter methods.

Function Overloading

C++ and D follow different rules for function overloading. D source code, even when calling extern (C++) functions, will still follow D overloading rules.

Storage Allocation

C++ code explicitly manages memory with calls to ::operator new() and ::operator delete(). D allocates memory using the D garbage collector, so no explicit delete's are necessary. D's new and delete are not compatible with C++'s ::operator new and ::operator delete. Attempting to allocate memory with C++ ::operator new and deallocate it with D's delete, or vice versa, will result in miserable failure.

D can still explicitly allocate memory using std.c.stdlib.malloc() and std.c.stdlib.free(), these are useful for connecting to C++ functions that expect malloc'd buffers, etc.

If pointers to D garbage collector allocated memory are passed to C++ functions, it's critical to ensure that that memory will not be collected by the garbage collector before the C++ function is done with it. This is accomplished by:

  • Making a copy of the data using std.c.stdlib.malloc() and passing the copy instead.
  • Leaving a pointer to it on the stack (as a parameter or automatic variable), as the garbage collector will scan the stack.
  • Leaving a pointer to it in the static data segment, as the garbage collector will scan the static data segment.
  • Registering the pointer with the garbage collector with the std.gc.addRoot() or std.gc.addRange() calls.

An interior pointer to the allocated memory block is sufficient to let the GC know the object is in use; i.e. it is not necessary to maintain a pointer to the beginning of the allocated memory.

The garbage collector does not scan the stacks of threads not created by the D Thread interface. Nor does it scan the data segments of other DLL's, etc.

Data Type Compatibility

D And C Type Equivalence
D type | C type
void | void
byte | signed char
ubyte | unsigned char
char | char (chars are unsigned in D)
wchar | wchar_t (when sizeof(wchar_t) is 2)
dchar | wchar_t (when sizeof(wchar_t) is 4)
short | short
ushort | unsigned short
int | int
uint | unsigned
long | long long
ulong | unsigned long long
float | float
double | double
real | long double
ifloat | no equivalent
idouble | no equivalent
ireal | no equivalent
cfloat | no equivalent
cdouble | no equivalent
creal | no equivalent
struct | struct
union | union
enum | enum
class | no equivalent
type* | type *
no equivalent | type &
type[dim] | type[dim]
type[dim]* | type(*)[dim]
type[] | no equivalent
type[type] | no equivalent
type function(parameters) | type(*)(parameters)
type delegate(parameters) | no equivalent

These equivalents hold for most 32 bit C++ compilers. The C++ standard does not pin down the sizes of the types, so some care is needed.

Structs and Unions

D structs and unions are analogous to C's.

C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific #pragma's. D supports explicit alignment attributes that correspond to the C compiler's rules. Check what alignment the C code is using, and explicitly set it for the D struct declaration.

D does not support bit fields. If needed, they can be emulated with shift and mask operations. htod will convert bit fields to inline functions that do the right shift and masks.

Object Construction and Destruction

Similarly to storage allocation and deallocation, objects constructed in D code should be destructed in D, and objects constructed in C++ should be destructed in C++ code.

Special Member Functions

D cannot call C++ special member functions, and vice versa. These include constructors, destructors, conversion operators, operator overloading, and allocators.

Runtime Type Identification

D runtime type identification uses completely different techniques than C++. The two are incompatible.

C++ Class Objects by Value

D can access POD (Plain Old Data) C++ structs, and it can access C++ class virtual functions by reference. It cannot access C++ classes by value.

C++ Templates

D templates have little in common with C++ templates, and it is very unlikely that any sort of reasonable method could be found to express C++ templates in a link-compatible way with D.

This means that the C++ STL, and C++ Boost, likely will never be accessible from D.

Exception Handling

D and C++ exception handling are completely different. Throwing exceptions across the boundaries between D and C++ code will likely not work.

Future Developments

How the upcoming C++0x standard will affect this is not known.

Over time, more aspects of the C++ ABI may be accessible directly from D.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Portability - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Portability

It's good software engineering practice to minimize gratuitous portability problems in the code. Techniques to minimize potential portability problems are:

  • The integral and floating type sizes should be considered as minimums. Algorithms should be designed to continue to work properly if the type size increases.
  • Floating point computations can be carried out at a higher precision than the size of the floating point variable can hold. Floating point algorithms should continue to work properly if precision is arbitrarily increased.
  • Avoid depending on the order of side effects in a computation that may get reordered by the compiler. For example:
    a + b + c

    can be evaluated as (a + b) + c, a + (b + c), (a + c) + b, (c + b) + a, etc. Parentheses control operator precedence, parentheses do not control order of evaluation.

    If the operands of an associative operator + or * are floating point values, the expression is not reordered.

  • Avoid dependence on byte order; i.e. whether the CPU is big-endian or little-endian.
  • Avoid dependence on the size of a pointer or reference being the same size as a particular integral type.
  • If size dependencies are inevitable, put an assert in the code to verify it:
    assert(int.sizeof == (int*).sizeof);

32 to 64 Bit Portability

64 bit processors and operating systems are here. With that in mind:

  • Integral types will remain the same sizes between 32 and 64 bit code.
  • Pointers and object references will increase in size from 4 bytes to 8 bytes going from 32 to 64 bit code.
  • Use size_t as an alias for an unsigned integral type that can span the address space. Array indices should be of type size_t.
  • Use ptrdiff_t as an alias for a signed integral type that can span the address space. A type representing the difference between two pointers should be of type ptrdiff_t.
  • The .length, .size, .sizeof, .offsetof and .alignof properties will be of type size_t.

Endianness

Endianness refers to the order in which multibyte types are stored. The two main orders are big endian and little endian. The compiler predefines the version identifier BigEndian or LittleEndian depending on the order of the target system. The x86 systems are all little endian.

The times when endianness matters are:

  • When reading data from an external source (like a file) written in a different endian format.
  • When reading or writing individual bytes of a multibyte type like longs or doubles.

OS Specific Code

System specific code is handled by isolating the differences into separate modules. At compile time, the correct system specific module is imported.

Minor differences can be handled by constant defined in a system specific import, and then using that constant in an IfStatement or StaticIfStatement.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Named Character Entities - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Named Character Entities

NamedCharacterEntity:
    & Identifier ;

D supports the full list of named character entities from HTML 5. However, dmd does not yet support named entities which contain multiple code points. Below is a partial list of the named character entities. See the HTML 5 Spec for the full list.

Note: Not all will display properly in the Symbol column in all browsers.

Named Character Entities
Name | Value | Symbol
quot | 34 | "
amp | 38 | &
lt | 60 | <
gt | 62 | >
OElig | 338 | Œ
oelig | 339 | œ
Scaron | 352 | Š
scaron | 353 | š
Yuml | 376 | Ÿ
circ | 710 | ˆ
tilde | 732 | ˜
ensp | 8194 |
emsp | 8195 |
thinsp | 8201 |
zwnj | 8204 | ‌
zwj | 8205 | ‍
lrm | 8206 | ‎
rlm | 8207 | ‏
ndash | 8211 | –
mdash | 8212 | —
lsquo | 8216 | ‘
rsquo | 8217 | ’
sbquo | 8218 | ‚
ldquo | 8220 | “
rdquo | 8221 | ”
bdquo | 8222 | „
dagger | 8224 | †
Dagger | 8225 | ‡
permil | 8240 | ‰
lsaquo | 8249 | ‹
rsaquo | 8250 | ›
euro | 8364 | €
Latin-1 (ISO-8859-1) Entities
nbsp | 160 |
iexcl | 161 | ¡
cent | 162 | ¢
pound | 163 | £
curren | 164 | ¤
yen | 165 | ¥
brvbar | 166 | ¦
sect | 167 | §
uml | 168 | ¨
copy | 169 | ©
ordf | 170 | ª
laquo | 171 | «
not | 172 | ¬
shy | 173 |
reg | 174 | ®
macr | 175 | ¯
deg | 176 | °
plusmn | 177 | ±
sup2 | 178 | ²
sup3 | 179 | ³
acute | 180 | ´
micro | 181 | µ
para | 182 | ¶
middot | 183 | ·
cedil | 184 | ¸
sup1 | 185 | ¹
ordm | 186 | º
raquo | 187 | »
frac14 | 188 | ¼
frac12 | 189 | ½
frac34 | 190 | ¾
iquest | 191 | ¿
Agrave | 192 | À
Aacute | 193 | Á
Acirc | 194 | Â
Atilde | 195 | Ã
Auml | 196 | Ä
Aring | 197 | Å
AElig | 198 | Æ
Ccedil | 199 | Ç
Egrave | 200 | È
Eacute | 201 | É
Ecirc | 202 | Ê
Euml | 203 | Ë
Igrave | 204 | Ì
Iacute | 205 | Í
Icirc | 206 | Î
Iuml | 207 | Ï
ETH | 208 | Ð
Ntilde | 209 | Ñ
Ograve | 210 | Ò
Oacute | 211 | Ó
Ocirc | 212 | Ô
Otilde | 213 | Õ
Ouml | 214 | Ö
times | 215 | ×
Oslash | 216 | Ø
Ugrave | 217 | Ù
Uacute | 218 | Ú
Ucirc | 219 | Û
Uuml | 220 | Ü
Yacute | 221 | Ý
THORN | 222 | Þ
szlig | 223 | ß
agrave | 224 | à
aacute | 225 | á
acirc | 226 | â
atilde | 227 | ã
auml | 228 | ä
aring | 229 | å
aelig | 230 | æ
ccedil | 231 | ç
egrave | 232 | è
eacute | 233 | é
ecirc | 234 | ê
euml | 235 | ë
igrave | 236 | ì
iacute | 237 | í
icirc | 238 | î
iuml | 239 | ï
eth | 240 | ð
ntilde | 241 | ñ
ograve | 242 | ò
oacute | 243 | ó
ocirc | 244 | ô
otilde | 245 | õ
ouml | 246 | ö
divide | 247 | ÷
oslash | 248 | ø
ugrave | 249 | ù
uacute | 250 | ú
ucirc | 251 | û
uuml | 252 | ü
yacute | 253 | ý
thorn | 254 | þ
yuml | 255 | ÿ
Symbols and Greek letter entities
fnof | 402 | ƒ
Alpha | 913 | Α
Beta | 914 | Β
Gamma | 915 | Γ
Delta | 916 | Δ
Epsilon | 917 | Ε
Zeta | 918 | Ζ
Eta | 919 | Η
Theta | 920 | Θ
Iota | 921 | Ι
Kappa | 922 | Κ
Lambda | 923 | Λ
Mu | 924 | Μ
Nu | 925 | Ν
Xi | 926 | Ξ
Omicron | 927 | Ο
Pi | 928 | Π
Rho | 929 | Ρ
Sigma | 931 | Σ
Tau | 932 | Τ
Upsilon | 933 | Υ
Phi | 934 | Φ
Chi | 935 | Χ
Psi | 936 | Ψ
Omega | 937 | Ω
alpha | 945 | α
beta | 946 | β
gamma | 947 | γ
delta | 948 | δ
epsilon | 949 | ε
zeta | 950 | ζ
eta | 951 | η
theta | 952 | θ
iota | 953 | ι
kappa | 954 | κ
lambda | 955 | λ
mu | 956 | μ
nu | 957 | ν
xi | 958 | ξ
omicron | 959 | ο
pi | 960 | π
rho | 961 | ρ
sigmaf | 962 | ς
sigma | 963 | σ
tau | 964 | τ
upsilon | 965 | υ
phi | 966 | φ
chi | 967 | χ
psi | 968 | ψ
omega | 969 | ω
thetasym | 977 | ϑ
upsih | 978 | ϒ
piv | 982 | ϖ
bull | 8226 | •
hellip | 8230 | …
prime | 8242 | ′
Prime | 8243 | ″
oline | 8254 | ‾
frasl | 8260 | ⁄
weierp | 8472 | ℘
image | 8465 | ℑ
real | 8476 | ℜ
trade | 8482 | ™
alefsym | 8501 | ℵ
larr | 8592 | ←
uarr | 8593 | ↑
rarr | 8594 | →
darr | 8595 | ↓
harr | 8596 | ↔
crarr | 8629 | ↵
lArr | 8656 | ⇐
uArr | 8657 | ⇑
rArr | 8658 | ⇒
dArr | 8659 | ⇓
hArr | 8660 | ⇔
forall | 8704 | ∀
part | 8706 | ∂
exist | 8707 | ∃
empty | 8709 | ∅
nabla | 8711 | ∇
isin | 8712 | ∈
notin | 8713 | ∉
ni | 8715 | ∋
prod | 8719 | ∏
sum | 8721 | ∑
minus | 8722 | −
lowast | 8727 | ∗
radic | 8730 | √
prop | 8733 | ∝
infin | 8734 | ∞
ang | 8736 | ∠
and | 8743 | ∧
or | 8744 | ∨
cap | 8745 | ∩
cup | 8746 | ∪
int | 8747 | ∫
there4 | 8756 | ∴
sim | 8764 | ∼
cong | 8773 | ≅
asymp | 8776 | ≈
ne | 8800 | ≠
equiv | 8801 | ≡
le | 8804 | ≤
ge | 8805 | ≥
sub | 8834 | ⊂
sup | 8835 | ⊃
nsub | 8836 | ⊄
sube | 8838 | ⊆
supe | 8839 | ⊇
oplus | 8853 | ⊕
otimes | 8855 | ⊗
perp | 8869 | ⊥
sdot | 8901 | ⋅
lceil | 8968 | ⌈
rceil | 8969 | ⌉
lfloor | 8970 | ⌊
rfloor | 8971 | ⌋
loz | 9674 | ◊
spades | 9824 | ♠
clubs | 9827 | ♣
hearts | 9829 | ♥
diams | 9830 | ♦
lang | 10216 | ⟨
rang | 10217 | ⟩
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Memory-Safe-D-Spec - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Memory-Safe-D-Spec

Memory Safety for a program is defined as it being impossible for the program to corrupt memory. Therefore, the Safe D consists only of programming language features that are guaranteed to never result in memory corruption.

Safe D is enabled on a per-module basis by compiling with the -safe compiler switch.

Proscribed Forms

  • Inline assembler.
  • Casting away const or immutable attributes.
  • Casting away shared attributes.
  • Casting from one pointer type to another pointer type, except for:
    • casting to void* is allowed
    • casting from a pointer to an arithmetic type to a pointer to another arithmetic type of the same or smaller size is allowed
  • Casting from a non-pointer type to a pointer type.

A safe module can import and use the public interface of a system module.

Limitations

Safe D does not imply that code is portable, uses only sound programming practices, is free of byte order dependencies, or other bugs. It is focussed only on eliminating memory corruption possibilities.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Application Binary Interface - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Application Binary Interface

A D implementation that conforms to the D ABI (Application Binary Interface) will be able to generate libraries, DLL's, etc., that can interoperate with D binaries built by other implementations.

C ABI

The C ABI referred to in this specification means the C Application Binary Interface of the target system. C and D code should be freely linkable together, in particular, D code shall have access to the entire C ABI runtime library.

Endianness

The endianness (byte order) of the layout of the data will conform to the endianness of the target machine. The Intel x86 CPUs are little endian meaning that the value 0x0A0B0C0D is stored in memory as: 0D 0C 0B 0A.

Basic Types

bool | 8 bit byte with the values 0 for false and 1 for true
byte | 8 bit signed value
ubyte | 8 bit unsigned value
short | 16 bit signed value
ushort | 16 bit unsigned value
int | 32 bit signed value
uint | 32 bit unsigned value
long | 64 bit signed value
ulong | 64 bit unsigned value
cent | 128 bit signed value
ucent | 128 bit unsigned value
float | 32 bit IEEE 754 floating point value
double | 64 bit IEEE 754 floating point value
real | implementation defined floating point value, for x86 it is 80 bit IEEE 754 extended real

Delegates

Delegates are fat pointers with two parts:

Delegate Layout
offset | property | contents
0 | .ptr | context pointer
ptrsize | .funcptr | pointer to function

The context pointer can be a class this reference, a struct this pointer, a pointer to a closure (nested functions) or a pointer to an enclosing function's stack frame (nested functions).

Structs

Conforms to the target's C ABI struct layout.

Classes

An object consists of:

Class Object Layout
size | property | contents
ptrsize | .__vptr | pointer to vtable
ptrsize | .__monitor | monitor
... | ... | super's non-static fields and super's interface vptrs, from least to most derived
... | named fields | non-static fields
ptrsize... |  | vptr's for any interfaces implemented by this class in left to right, most to least derived, order

The vtable consists of:

Virtual Function Pointer Table Layout
size | contents
ptrsize | pointer to instance of TypeInfo
ptrsize... | pointers to virtual member functions

Casting a class object to an interface consists of adding the offset of the interface's corresponding vptr to the address of the base of the object. Casting an interface ptr back to the class type it came from involves getting the correct offset to subtract from it from the object.Interface entry at vtbl[0]. Adjustor thunks are created and pointers to them stored in the method entries in the vtbl[] in order to set the this pointer to the start of the object instance corresponding to the implementing method.

An adjustor thunk looks like:

 ADD EAX,offset
  JMP method

The leftmost side of the inheritance graph of the interfaces all share their vptrs, this is the single inheritance model. Every time the inheritance graph forks (for multiple inheritance) a new vptr is created and stored in the class' instance. Every time a virtual method is overridden, a new vtbl[] must be created with the updated method pointers in it.

The class definition:

class XXXX {
  ....
};

Generates the following:

  • An instance of Class called ClassXXXX.
  • A type called StaticClassXXXX which defines all the static members.
  • An instance of StaticClassXXXX called StaticXXXX for the static members.

Interfaces

An interface is a pointer to a pointer to a vtbl[]. The vtbl[0] entry is a pointer to the corresponding instance of the object.Interface class. The rest of the vtbl[1..$] entries are pointers to the virtual functions implemented by that interface, in the order that they were declared.

A COM interface differs from a regular interface in that there is no object.Interface entry in vtbl[0]; the entries vtbl[0..$] are all the virtual function pointers, in the order that they were declared. This matches the COM object layout used by Windows.

A C++ interface differs from a regular interface in that it matches the layout of a C++ class using single inheritance on the target machine.

Arrays

A dynamic array consists of:

Dynamic Array Layout
offset | property | contents
0 | .length | array dimension
size_t | .ptr | pointer to array data

A dynamic array is declared as:

type[] array;

whereas a static array is declared as:

type[dimension] array;

Thus, a static array always has the dimension statically available as part of the type, and so it is implemented like in C. Static array's and Dynamic arrays can be easily converted back and forth to each other.

Associative Arrays

Associative arrays consist of a pointer to an opaque, implementation defined type. The current implementation is contained in and defined by rt/aaA.d.

Reference Types

D has reference types, but they are implicit. For example, classes are always referred to by reference; this means that class instances can never reside on the stack or be passed as function parameters.

When passing a static array to a function, the result, although declared as a static array, will actually be a reference to a static array. For example:

int[3] abc;

Passing abc to functions results in these implicit conversions:

void func(int[3] array); // actually <reference to><array[3] of><int>
void func(int* p);       // abc is converted to a pointer
                         // to the first element
void func(int[] array);	 // abc is converted to a dynamic array

Name Mangling

D accomplishes typesafe linking by mangling a D identifier to include scope and type information.

MangledName:
    _D QualifiedName Type
    _D QualifiedName M Type

QualifiedName:
    SymbolName
    SymbolName QualifiedName

SymbolName:
    LName
    TemplateInstanceName

The M means that the symbol is a function that requires a this pointer.

Template Instance Names have the types and values of its parameters encoded into it:

TemplateInstanceName:
    Number __T LName TemplateArgs Z

TemplateArgs:
    TemplateArg
    TemplateArg TemplateArgs

TemplateArg:
    T Type
    V Type Value
    S LName

Value:
    n
    Number
    i Number
    N Number
    e HexFloat
    c HexFloat c HexFloat
    A Number Value...
    S 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
n
is for null arguments.
Number
is for positive numeric literals (including character literals).
N Number
is for negative numeric literals.
e HexFloat
is for real and imaginary floating point literals.
c HexFloat c HexFloat
is for complex floating point literals.
Width Number _ HexDigits
Width is whether the characters are 1 byte (a), 2 bytes (w) or 4 bytes (d) in size. Number is the number of characters in the string. The HexDigits are the hex data for the string.
A Number Value...
An array or asssociative array literal. Number is the length of the array. Value is repeated Number times for a normal array, and 2 * Number times for an associative array.
S Number Value...
A struct literal. Value is repeated Number times.
Name:
    Namestart
    Namestart Namechars

Namestart:
    _
    Alpha

Namechar:
    Namestart
    Digit

Namechars:
    Namechar
    Namechar Namechars

A Name is a standard D identifier.

LName:
    Number Name

Number:
    Digit
    Digit Number

Digit:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

An LName is a name preceded by a Number giving the number of characters in the Name.

Type Mangling

Types are mangled using a simple linear scheme:

Type:
    Shared
    Const
    Immutable
    Wild
    TypeArray
    TypeNewArray
    TypeStaticArray
    TypeAssocArray
    TypePointer
    TypeFunction
    TypeIdent
    TypeClass
    TypeStruct
    TypeEnum
    TypeTypedef
    TypeDelegate
    TypeNone
    TypeVoid
    TypeByte
    TypeUbyte
    TypeShort
    TypeUshort
    TypeInt
    TypeUint
    TypeLong
    TypeUlong
    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

TypeNewArray:
    Ne Type

TypeStaticArray:
    G Number Type

TypeAssocArray:
    H Type Type

TypePointer:
    P Type

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

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

TypeIdent:
    I QualifiedName

TypeClass:
    C QualifiedName

TypeStruct:
    S QualifiedName

TypeEnum:
    E QualifiedName

TypeTypedef:
    T QualifiedName

TypeDelegate:
    D TypeFunction

TypeNone:
    n

TypeVoid:
    v

TypeByte:
    g

TypeUbyte:
    h

TypeShort:
    s

TypeUshort:
    t

TypeInt:
    i

TypeUint:
    k

TypeLong:
    l

TypeUlong:
    m

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

Function Calling Conventions

The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system. Except that the extern (D) calling convention for Windows x86 is described here.

Register Conventions

  • EAX, ECX, EDX are scratch registers and can be destroyed by a function.
  • EBX, ESI, EDI, EBP must be preserved across function calls.
  • EFLAGS is assumed destroyed across function calls, except for the direction flag which must be forward.
  • The FPU stack must be empty when calling a function.
  • The FPU control word must be preserved across function calls.
  • Floating point return values are returned on the FPU stack. These must be cleaned off by the caller, even if they are not used.

Return Value

  • The types bool, byte, ubyte, short, ushort, int, uint, pointer, Object, and interfaces are returned in EAX.
  • long and ulong are returned in EDX,EAX, where EDX gets the most significant half.
  • float, double, real, ifloat, idouble, ireal are returned in ST0.
  • cfloat, cdouble, creal are returned in ST1,ST0 where ST1 is the real part and ST0 is the imaginary part.
  • Dynamic arrays are returned with the pointer in EDX and the length in EAX.
  • Associative arrays are returned in EAX.
  • References are returned as pointers in EAX.
  • Delegates are returned with the pointer to the function in EDX and the context pointer in EAX.
  • 1, 2 and 4 byte structs are returned in EAX.
  • 8 byte structs are returned in EDX,EAX, where EDX gets the most significant half.
  • For other struct sizes, the return value is stored through a hidden pointer passed as an argument to the function.
  • Constructors return the this pointer in EAX.

Parameters

The parameters to the non-variadic function:

    foo(a1, a2, ..., an);

are passed as follows:

a1
a2
...
an
hidden
this

where hidden is present if needed to return a struct value, and this is present if needed as the this pointer for a member function or the context pointer for a nested function.

The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met:

  • It fits in EAX.
  • It is not a 3 byte struct.
  • It is not a floating point type.

Parameters are always pushed as multiples of 4 bytes, rounding upwards, so the stack is always aligned on 4 byte boundaries. They are pushed most significant first. out and ref are passed as pointers. Static arrays are passed as pointers to their first element. On Windows, a real is pushed as a 10 byte quantity, a creal is pushed as a 20 byte quantity. On Linux, a real is pushed as a 12 byte quantity, a creal is pushed as two 12 byte quantities. The extra two bytes of pad occupy the ‘most significant’ position.

The callee cleans the stack.

The parameters to the variadic function:

    void foo(int p1, int p2, int[] p3...)
    foo(a1, a2, ..., an);

are passed as follows:

p1
p2
a3
hidden
this

The variadic part is converted to a dynamic array and the rest is the same as for non-variadic functions.

The parameters to the variadic function:

    void foo(int p1, int p2, ...)
    foo(a1, a2, a3, ..., an);

are passed as follows:

an
...
a3
a2
a1
_arguments
hidden
this

The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee.

Exception Handling

Windows

Conforms to the Microsoft Windows Structured Exception Handling conventions.

Linux

FreeBSD and OS X,

Uses static address range/handler tables. It is not compatible with the ELF/Mach-O exception handling tables. The stack is walked assuming it uses the EBP/RBP stack frame convention. The EBP/RBP convention must be used for every function that has an associated EH (Exception Handler) table.

For each function that has exception handlers, an EH table entry is generated.

EH Table Entry
field | description
void* | pointer to start of function
DHandlerTable* | pointer to corresponding EH data
uint | size in bytes of the function

The EH table entries are placed into the following special segments, which are concatenated by the linker.

EH Table Segment
Operating System | Segment Name
Windows | FI
Linux | .deh_eh
FreeBSD | .deh_eh
OS X | __deh_eh, __DATA

The rest of the EH data can be placed anywhere, it is immutable.

DHandlerTable
field | description
void* | pointer to start of function
uint | offset of ESP/RSP from EBP/RBP
uint | offset from start of function to return code
uint | number of entries in DHandlerInfo[]
DHandlerInfo[] | array of handler information

DHandlerInfo
field | description
uint | offset from function address to start of guarded section
uint | offset of end of guarded section
int | previous table index
uint | if != 0 offset to DCatchInfo data from start of table
void* | if not null, pointer to finally code to execute

DCatchInfo
field | description
uint | number of entries in DCatchBlock[]
DCatchBlock[] | array of catch information

DCatchBlock
field | description
ClassInfo | catch type
uint | offset from EBP/RBP to catch variable
void* | catch handler code

Garbage Collection

The interface to this is found in phobos/internal/gc.

Runtime Helper Functions

These are found in phobos/internal.

Module Initialization and Termination

All the static constructors for a module are aggregated into a single function, and a pointer to that function is inserted into the ctor member of the ModuleInfo instance for that module.

All the static denstructors for a module are aggregated into a single function, and a pointer to that function is inserted into the dtor member of the ModuleInfo instance for that module.

Unit Testing

All the unit tests for a module are aggregated into a single function, and a pointer to that function is inserted into the unitTest member of the ModuleInfo instance for that module.

Symbolic Debugging

D has types that are not represented in existing C or C++ debuggers. These are dynamic arrays, associative arrays, and delegates. Representing these types as structs causes problems because function calling conventions for structs are often different than that for these types, which causes C/C++ debuggers to misrepresent things. For these debuggers, they are represented as a C type which does match the calling conventions for the type. The dmd compiler will generate only C symbolic type info with the -gc compiler switch.

Types for C Debuggers
D type | C representation
dynamic array | unsigned long long
associative array | void*
delegate | long long
dchar | unsigned long

For debuggers that can be modified to accept new types, the following extensions help them fully support the types.

Codeview Debugger Extensions

The D dchar type is represented by the special primitive type 0x78.

D makes use of the Codeview OEM generic type record indicated by LF_OEM (0x0015). The format is:

Codeview OEM Extensions for D
field size | 2 | 2 | 2 | 2 | 2 | 2
D Type | Leaf Index | OEM Identifier | recOEM | num indices | type index | type index
dynamic array | LF_OEM | OEM | 1 | 2 | @index | @element
associative array | LF_OEM | OEM | 2 | 2 | @key | @element
delegate | LF_OEM | OEM | 3 | 2 | @this | @function

Where:

OEM | 0x42
index | type index of array index
key | type index of key
element | type index of array element
this | type index of context pointer
function | type index of function

These extensions can be pretty-printed by obj2asm.

The Ddbg debugger supports them.

Dwarf Debugger Extensions

The following leaf types are added:

Dwarf Extensions for D
D type | Identifier | Value | Format
dynamic array | DW_TAG_darray_type | 0x41 | DW_AT_type is element type
associative array | DW_TAG_aarray_type | 0x42 | DW_AT_type, is element type, DW_AT_containing_type key type
delegate | DW_TAG_delegate_type | 0x43 | DW_AT_type, is function type, DW_AT_containing_type is ‘this’ type

These extensions can be pretty-printed by dumpobj.

The ZeroBUGS debugger supports them.

Note that these Dwarf extensions have been removed as they conflict with recent gcc additions.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Phobos Runtime Library

Phobos is the standard runtime library that comes with the D language compiler. Also, check out the wiki for Phobos.

Philosophy

Each module in Phobos conforms as much as possible to the following design goals. These are goals rather than requirements because D is not a religion, it's a programming language, and it recognizes that sometimes the goals are contradictory and counterproductive in certain situations, and programmers have jobs that need to get done.
Machine and Operating System Independent Interfaces
It's pretty well accepted that gratuitous non-portability should be avoided. This should not be construed, however, as meaning that access to unusual features of an operating system should be prevented.
Simple Operations should be Simple
A common and simple operation, like writing an array of bytes to a file, should be simple to code. I haven't seen a class library yet that simply and efficiently implemented common, basic file I/O operations.
Classes should strive to be independent of one another
It's discouraging to pull in a megabyte of code bloat by just trying to read a file into an array of bytes. Class independence also means that classes that turn out to be mistakes can be deprecated and redesigned without forcing a rewrite of the rest of the class library.
No pointless wrappers around C runtime library functions or OS API functions
D provides direct access to C runtime library functions and operating system API functions. Pointless D wrappers around those functions just adds blather, bloat, baggage and bugs.
Class implementations should use DBC
This will prove that DBC (Contract Programming) is worthwhile. Not only will it aid in debugging the class, but it will help every class user use the class correctly. DBC in the class library will have great leverage.
Use Exceptions for Error Handling
See Error Handling in D.

Imports

Runtime library modules can be imported with the import statement. Each module falls into one of several packages:
std
These are the core modules.

std.windows
Modules specific to the Windows operating system.

std.linux
Modules specific to the Linux operating system.

std.c
Modules that are simply interfaces to C functions. For example, interfaces to standard C library functions will be in std.c, such as std.c.stdio would be the interface to C's stdio.h.

std.c.windows
Modules corresponding to the C Windows API functions.

std.c.linux
Modules corresponding to the C Linux API functions.

etc
This is the root of a hierarchy of modules mirroring the std hierarchy. Modules in etc are not standard D modules. They are here because they are experimental, or for some other reason are not quite suitable for std, although they are still useful.

std: Core library modules
std.base64
Functions that operate on ASCII characters.
std.base64
Encode/decode base64 format.
std.bigint
Arbitrary-precision ('bignum') arithmetic
std.compiler
Information about the D compiler implementation.
std.conv
Conversion of strings to integers.
std.datetime
Date and time-related types and functions.
std.file
Basic file operations like read, write, append.
std.format
Formatted conversions of values to strings.
std.math
Include all the usual math functions like sin, cos, atan, etc.
std.md5
Compute MD5 digests.
std.mmfile
Memory mapped files.
object
The root class of the inheritance hierarchy
std.outbuffer
Assemble data into an array of bytes
std.path
Manipulate file names, path names, etc.
std.process
Create/destroy threads.
std.random
Random number generation.
std.regexp
The usual regular expression functions.
std.socket
Sockets.
std.socketstream
Stream for a blocking, connected Socket.
std.stdint
Integral types for various purposes.
std.stdio
Standard I/O.
std.cstream
Stream I/O.
std.stream
Stream I/O.
std.string
Basic string operations not covered by array ops.
std.system
Inquire about the CPU, operating system.
std.base64
Functions that operate on Unicode characters.
std.uri
Encode and decode Uniform Resource Identifiers (URIs).
std.utf
Encode and decode utf character encodings.
std.zip
Read/write zip archives.
std.zlib
Compression / Decompression of data.

std.windows: Modules specific to the Windows operating system
std.windows.syserror
Convert Windows error codes to strings.

std.linux: Modules specific to the Linux operating system

std.c: Interface to C functions
std.c.stdio
Interface to C stdio functions like printf().

std.c.windows: Interface to C Windows functions
std.c.windows.windows
Interface to Windows APIs

std.c.linux: Interface to C Linux functions
std.c.linux.linux
Interface to Linux APIs

std.c.stdio
int printf(char* format, ...)
C printf() function.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

object

Forms the symbols available to all D programs. Includes Object, which is the root of the class object hierarchy. This module is implicitly imported.

License:
Boost License 1.0.

Authors:
Walter Bright, Sean Kelly

class Object;
All D class objects inherit from Object.

string toString();
Convert Object to a human readable string.

nothrow @trusted size_t toHash();
Compute hash function for Object.

int opCmp(Object o);
Compare with another Object obj.

Returns:
this < obj | < 0
this == obj | 0
this > obj | > 0
this < obj | < 0
this == obj | 0
this > obj | > 0

bool opEquals(Object o);
Returns !=0 if this object does have the same contents as obj.

static Object factory(string classname);
Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

Returns:
null if failed

bool opEquals(const Object lhs, const Object rhs);
Returns true if lhs and rhs are equal.

struct Interface;
Information about an interface. When an object is accessed via an interface, an Interface* appears as the first entry in its vtbl.

TypeInfo_Class classinfo;
.classinfo for this interface (not for containing class)

ptrdiff_t offset;
offset to Interface 'this' from Object 'this'

alias TypeInfo_Class Classinfo;
Runtime type information about a class. Can be retrieved for any class type or instance by using the .classinfo property. A pointer to this appears as the first entry in the class's vtbl[].

struct OffsetTypeInfo;
Array of pairs giving the offset and type information for each member in an aggregate.

size_t offset;
Offset of member from start of object

TypeInfo ti;
TypeInfo for this member

class TypeInfo;
Runtime type information about a type. Can be retrieved for any type using a TypeidExpression.

const nothrow @trusted size_t getHash(in void* p);
Returns a hash of the instance of a type.

const bool equals(in void* p1, in void* p2);
Compares two instances for equality.

const int compare(in void* p1, in void* p2);
Compares two instances for <, ==, or >.

const pure nothrow @property @safe size_t tsize();
Returns size of the type.

const void swap(void* p1, void* p2);
Swaps two instances of the type.

const pure nothrow @property const(TypeInfo) next();
Get TypeInfo for 'next' type, as defined by what kind of type this is, null if none.

const pure nothrow @safe const(void)[] init();
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.

const pure nothrow @property @safe uint flags();
Get flags for type: 1 means GC should scan for pointers

const const(OffsetTypeInfo)[] offTi();
Get type information on the contents of the type; null if not available

const void destroy(void* p);
Run the destructor on the object and all its sub-objects

const void postblit(void* p);
Run the postblit on the object and all its sub-objects

const pure nothrow @property @safe size_t talign();
Return alignment of type

const pure nothrow @property @safe immutable(void)* rtInfo();
Return info used by the garbage collector to do precise collection.

class TypeInfo_Class: object.TypeInfo;
Runtime type information about a class. Can be retrieved from an object instance by using the .classinfo property.

byte[] 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

static const(TypeInfo_Class) find(in char[] classname);
Search all modules for TypeInfo_Class corresponding to classname.

Returns:
null if not found

const Object create();
Create instance of Object represented by 'this'.

class Throwable;
The base class of all thrown objects.

All thrown objects must inherit from Throwable. Class 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 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.

string msg;
A message describing the error.

string file;
size_t line;
The file name and line number of the D source code corresponding with where the error was thrown from.

TraceInfo info;
The stack trace of where the error happened. This is an opaque object that can either be converted to string, or iterated over with foreach to extract the items in the stack trace (as strings).

Throwable next;
A reference to the next error in the list. This is used when a new Throwable is thrown from inside a catch block. The originally caught Exception will be chained to the new Throwable via this field.

void rt_setTraceHandler(TraceHandler h);
Overrides the default trace hander with a user-supplied version.

Parameters:
TraceHandler h The new trace handler. Set to null to use the default handler.

TraceHandler rt_getTraceHandler();
Return the current trace handler

Throwable.TraceInfo _d_traceContext(void* ptr = null);
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.

Parameters:
void* 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.

class Exception: object.Throwable;
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 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.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);
Creates a new instance of Exception. The next parameter is used internally and should be always be null when passed by user code. This constructor does not automatically throw the newly-created Exception; the throw statement should be used for that purpose.

alias Object.Monitor IMonitor;

void destroy(T)(T obj);
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 not initiate a GC cycle or free any GC memory.

pure nothrow size_t capacity(T)(T[] arr);
(Property) Get the current capacity of an array. The capacity is the number of elements that the array can grow to before the array must be extended/reallocated.

pure nothrow size_t reserve(T)(ref T[] arr, size_t newcapacity);
Try to reserve capacity for an array. The capacity is the number of elements that the array can grow to before the array must be extended/reallocated.

The return value is the new capacity of the array (which may be larger than the requested capacity).

void assumeSafeAppend(T)(T[] arr);
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 you are sure no elements are in use beyond the array in the memory block. If there are, those elements could 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.

bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2);
Helper function used to see if two containers of different types have the same contents in the same sequence.

template RTInfo(T)
Create RTInfo for type T

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.algorithm

Category | Functions
Searching | balancedParens boyerMooreFinder canFind count countUntil endsWith commonPrefix find findAdjacent findAmong findSkip findSplit findSplitAfter findSplitBefore indexOf minCount minPos mismatch skipOver startsWith until
Comparison | cmp equal levenshteinDistance levenshteinDistanceAndPath max min mismatch
Iteration | filter filterBidirectional group joiner map reduce splitter uniq
Sorting | completeSort isPartitioned isSorted makeIndex partialSort partition partition3 schwartzSort sort topN topNCopy
Set operations | largestPartialIntersection largestPartialIntersectionWeighted nWayUnion setDifference setIntersection setSymmetricDifference setUnion
Mutation | bringToFront copy fill initializeAll move moveAll moveSome remove reverse swap swapRanges uninitializedFill

Implements algorithms oriented mainly towards processing of sequences. Some functions are semantic equivalents or supersets of those found in the <algorithm> header in Alexander Stepanov's Standard Template Library for C++.

Many functions in this module are parameterized with a function or a predicate. The predicate may be passed either as a function name, a delegate name, a functor name, or a compile-time string. The string may consist of any legal D expression that uses the symbol a (for unary functions) or the symbols a and 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 "a == b" for unordered operations and "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);  // predicate as string
                    // (no ambiguity with array name)
sort(a);            // no predicate, "a < b" is implicit

Cheat Sheet
Function Name | Description
Searching
balancedParens | balancedParens("((1 + 1) / 2)") returns true because the string has balanced parentheses.
boyerMooreFinder | find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm.
canFind | canFind("hello world", "or") returns true.
count | Counts elements that are equal to a specified value or satisfy a predicate. count([1, 2, 1], 1) returns 2 and count!"a < 0"([1, -3, 0]) returns 1.
countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4.
endsWith | endsWith("rocks", "ks") returns true.
find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to std.range.sortedRange.)
findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4].
findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx".
findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, 'c') advances a to "cde" and returns true.
findSplit | findSplit("abcdefg", "de") returns the three ranges "abc", "de", and "fg".
findSplitAfter | findSplitAfter("abcdefg", "de") returns the two ranges "abcde" and "fg".
findSplitBefore | findSplitBefore("abcdefg", "de") returns the two ranges "abc" and "defg".
minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3).
minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element.
skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true.
startsWith | startsWith("hello, world", "hello") returns true.
until | Lazily iterates a range until a specific value is found.
Comparison
cmp | cmp("abc", "abcd") is -1, cmp("abc", aba") is 1, and cmp("abc", "abc") is 0.
equal | Compares ranges for element-by-element equality, e.g. equal([1, 2, 3], [1.0, 2.0, 3.0]) returns true.
levenshteinDistance | levenshteinDistance("kitten", "sitting") returns 3 by using the Levenshtein distance algorithm.
levenshteinDistanceAndPath | levenshteinDistanceAndPath("kitten", "sitting") returns tuple(3, "snnnsni") by using the Levenshtein distance algorithm.
max | max(3, 4, 2) returns 4.
min | min(3, 4, 2) returns 2.
mismatch | mismatch("oh hi", "ohayo") returns tuple(" hi", "ayo").
Iteration
filter | filter!"a > 0"([1, -1, 2, 0, -3]) iterates over elements 1, 2, and 0.
filterBidirectional | Similar to filter, but also provides back and popBack at a small increase in cost.
group | group([5, 2, 2, 3, 3]) returns a range containing the tuples tuple(5, 1), tuple(2, 2), and tuple(3, 2).
joiner | joiner(["hello", "world!"], ";") returns a range that iterates over the characters "hello; world!". No new string is created - the existing inputs are iterated.
map | map!"2 * a"([1, 2, 3]) lazily returns a range with the numbers 2, 4, 6.
reduce | reduce!"a + b"([1, 2, 3, 4]) returns 10.
splitter | Lazily splits a range by a separator.
uniq | Iterates over the unique elements in a range, which is assumed sorted.
Sorting
completeSort | If a = [10, 20, 30] and b = [40, 6, 15], then completeSort(a, b) leaves a = [6, 10, 15] and b = [20, 30, 40]. The range a must be sorted prior to the call, and as a result the combination std.range.chain(a, b) is sorted.
isPartitioned | isPartitioned!"a < 0"([-1, -2, 1, 0, 2]) returns true because the predicate is true for a portion of the range and false afterwards.
isSorted | isSorted([1, 1, 2, 3]) returns true.
makeIndex | Creates a separate index for a range.
partialSort | If a = [5, 4, 3, 2, 1], then partialSort(a, 3) leaves a[0 .. 3] = [1, 2, 3]. The other elements of a are left in an unspecified order.
partition | Partitions a range according to a predicate.
schwartzSort | Sorts with the help of the Schwartzian transform.
sort | Sorts.
topN | Separates the top elements in a range.
topNCopy | Copies out the top elements of a range.
Set operations
largestPartialIntersection | Copies out the values that occur most frequently in a range of ranges.
largestPartialIntersectionWeighted | Copies out the values that occur most frequently (multiplied by per-value weights) in a range of ranges.
nWayUnion | Computes the union of a set of sets implemented as a range of sorted ranges.
setDifference | Lazily computes the set difference of two or more sorted ranges.
setIntersection | Lazily computes the set difference of two or more sorted ranges.
setSymmetricDifference | Lazily computes the symmetric set difference of two or more sorted ranges.
setUnion | Lazily computes the set union of two or more sorted ranges.
Mutation
bringToFront | If a = [1, 2, 3] and b = [4, 5, 6, 7], bringToFront(a, b) leaves a = [4, 5, 6] and b = [7, 1, 2, 3].
copy | Copies a range to another. If a = [1, 2, 3] and b = new int[5], then copy(a, b) leaves b = [1, 2, 3, 0, 0] and returns b[3 .. $].
fill | Fills a range with a pattern, e.g., if a = new int[3], then fill(a, 4) leaves a = [4, 4, 4] and fill(a, [3, 4]) leaves a = [3, 4, 3].
initializeAll | If a = [1.2, 3.4], then initializeAll(a) leaves a = [double.init, double.init].
move | move(a, b) moves a into b. move(a) reads a destructively.
moveAll | Moves all elements from one range to another.
moveSome | Moves as many elements as possible from one range to another.
reverse | If a = [1, 2, 3], reverse(a) changes it to [3, 2, 1].
swap | Swaps two values.
swapRanges | Swaps all elements of two ranges.
uninitializedFill | Fills a range (assumed uninitialized) with a value.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Source:
std/algorithm.d

template map(fun...) if (fun.length >= 1)
auto map(Range)(Range r) if (isInputRange!(Unqual!Range));

Implements the homonym function (also known as transform) present in many languages of functional flavor. The call map!(fun)(range) returns a range of which elements are obtained by applying fun(x) left to right for all x in range. The original ranges are not changed. Evaluation is done lazily.

Example:
int[] arr1 = [ 1, 2, 3, 4 ];
int[] arr2 = [ 5, 6 ];
auto squares = map!("a * a")(chain(arr1, arr2));
assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));

Multiple functions can be passed to map. In that case, the element type of map is a tuple containing one element for each function.

Example:
auto arr1 = [ 1, 2, 3, 4 ];
foreach (e; map!("a + a", "a * a")(arr1))
{
    writeln(e[0], " ", e[1]);
}

You may alias map with some function(s) to a symbol and use it separately:

alias map!(to!string) stringize;
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));

template reduce(fun...) if (fun.length >= 1)
auto reduce(Args...)(Args args) if (Args.length > 0 && Args.length <= 2 && isIterable!(Args[$ - 1]));

Implements the homonym function (also known as accumulate, compress, inject, or foldl) present in various programming languages of functional flavor. The call reduce!(fun)(seed, range) first assigns seed to an internal variable result, also called the accumulator. Then, for each element x in range, result = fun(result, x) gets evaluated. Finally, result is returned. The one-argument version reduce!(fun)(range) works similarly, but it uses the first element of the range as the seed (the range must be non-empty).

Many aggregate range operations turn out to be solved with reduce quickly and easily. The example below illustrates reduce's remarkable power and flexibility.

Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto sum = reduce!("a + b")(0, arr);
assert(sum == 15);

// Compute the maximum of all elements
auto largest = reduce!(max)(arr);
assert(largest == 5);

// Compute the number of odd elements
auto odds = reduce!("a + (b & 1)")(0, arr);
assert(odds == 3);

// Compute the sum of squares
auto ssquares = reduce!("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(r1 == 112.5);

Multiple functions:
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 reduce accepts multiple functions. If two or more functions are passed, reduce returns a std.typecons.Tuple object with one member per passed-in function. The number of seeds must be correspondingly increased.

Example:
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!(double, double)
assert(r[0] == 2);  // minimum
assert(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(r[0] == 35);  // sum
assert(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);

void fill(Range, Value)(Range range, Value filler);
Fills range with a filler.

Example:
int[] a = [ 1, 2, 3, 4 ];
fill(a, 5);
assert(a == [ 5, 5, 5, 5 ]);

void fill(Range1, Range2)(Range1 range, Range2 filler);
Fills range with a pattern copied from filler. The length of range does not have to be a multiple of the length of filler. If filler is empty, an exception is thrown.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
int[] b = [ 8, 9 ];
fill(a, b);
assert(a == [ 8, 9, 8, 9, 8 ]);

void uninitializedFill(Range, Value)(Range range, Value filler);
Fills a range with a value. Assumes that the range does not currently contain meaningful content. This is of interest for structs that define copy constructors (for all other types, fill and uninitializedFill are equivalent).

Example:
struct S { ... }
S[] s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
uninitializedFill(s, 42);
assert(s == [ 42, 42, 42, 42, 42 ]);

void initializeAll(Range)(Range range);
Initializes all elements of a range with their .init value. Assumes that the range does not currently contain meaningful content.

Example:
struct S { ... }
S[] s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
initializeAll(s);
assert(s == [ 0, 0, 0, 0, 0 ]);

template filter(alias pred) if (is(typeof(unaryFun!(pred))))
auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));

Implements the homonym function present in various programming languages of functional flavor. The call filter!(predicate)(range) returns a new range only containing elements x in range for which predicate(x) is true.

Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto small = filter!("a < 3")(arr);
assert(equal(small, [ 1, 2 ]));
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = filter!("a > 0")(chain(a, b));
assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = filter!("cast(int) a != a")(chain(c, a, b));
assert(equal(r1, [ 2.5 ]));

template filterBidirectional(alias pred)
auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range));

Similar to 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, std.range.retro can be applied against the filtered range.

Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
auto small = filterBidirectional!("a < 3")(arr);
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);

void move(T)(ref T source, ref T target);
T move(T)(ref T source);
Moves source into target via a destructive copy. Specifically:
  • If hasAliasing!T is true (see std.traits.hasAliasing), then the representation of source is bitwise copied into target and then source = T.init is evaluated.
  • Otherwise, target = source is evaluated.
See also std.exception.pointsTo.

Preconditions:
&source == &target || !pointsTo(source, source)

Range2 moveAll(Range1, Range2)(Range1 src, Range2 tgt);
For each element a in src and each element b in tgt in lockstep in increasing order, calls move(a, b). Returns the leftover portion of tgt. Throws an exeption if there is not enough room in tgt to acommodate all of src.

Preconditions:
walkLength(src) <= walkLength(tgt)

Tuple!(Range1, Range2) moveSome(Range1, Range2)(Range1 src, Range2 tgt);
For each element a in src and each element b in tgt in lockstep in increasing order, calls move(a, b). Stops when either src or tgt have been exhausted. Returns the leftover portions of the two ranges.

pure nothrow @trusted void swap(T)(ref T lhs, ref T rhs);
Swaps lhs and rhs. See also std.exception.pointsTo.

Preconditions:
!pointsTo(lhs, lhs) && !pointsTo(lhs, rhs) && !pointsTo(rhs, lhs) && !pointsTo(rhs, rhs)

template forward(args...)
Forwards function arguments with saving ref-ness.

Example:
int foo(int n) { return 1; }
int foo(ref int n) { return 2; }
int bar()(auto ref int x) { return foo(forward!x); }

assert(bar(1) == 1);
int i;
assert(bar(i) == 2);

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

auto splitter(Range, Separator)(Range r, Separator s);
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.

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.

Example:
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 = 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] ]));

auto splitter(Range, Separator)(Range r, Separator s);
Splits a range using 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.

auto joiner(RoR, Separator)(RoR r, Separator sep);
auto joiner(RoR)(RoR r);
Lazily joins a range of ranges with a separator. The separator itself is a range. If you do not provide a separator, then the ranges are joined directly without anything in between them.

Example:
assert(equal(joiner([""], "xyz"), ""));
assert(equal(joiner(["", ""], "xyz"), "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"));

auto uniq(alias pred = "a == b", Range)(Range r);
Iterates unique consecutive elements of the given range (functionality akin to the uniq system utility). Equivalence of elements is assessed by using the predicate pred, by default "a == b". If the given range is bidirectional, uniq also yields a bidirectional range.

Example:
int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][]));

struct Group(alias pred, R) if (isInputRange!(R));
Group!(pred, Range) group(alias pred = "a == b", Range)(Range r);
Similarly to uniq, group iterates unique consecutive elements of the given range. The element type is Tuple!(ElementType!R, uint) because it includes the count of equivalent elements seen. Equivalence of elements is assessed by using the predicate pred, by default "a == b".

Group is an input range if R is an input range, and a forward range in all other cases.

Example:
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) ][]));

R find(alias pred = "a == b", R, E)(R haystack, E needle);
Finds an individual element in an input range. Elements of haystack are compared with needle by using predicate pred. Performs Ο(walkLength(haystack)) evaluations of pred. See also STL's find.

To find the last occurence of needle in haystack, call find(retro(haystack), needle). See also std.range.retro.

Parameters:
haystack | The range searched in.
needle | The element searched for.

Constraints:
isInputRange!R && is(typeof(binaryFun!pred(haystack.front, needle) : bool))

Returns:
haystack advanced such that binaryFun!pred(haystack.front, needle) is true (if no such position exists, returns haystack after exhaustion).

Example:
assert(find("hello, world", ',') == ", world");
assert(find([1, 2, 3, 5], 4) == []);
assert(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);

R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
Finds a forward range in another. Elements are compared for equality. Performs Ο(walkLength(haystack) * walkLength(needle)) comparisons in the worst case. Specializations taking advantage of bidirectional or random access (where present) may accelerate search depending on the statistics of the two ranges' content.

Parameters:
haystack | The range searched in.
needle | The range searched for.

Constraints:
isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front) : bool))

Returns:
haystack advanced such that needle is a prefix of it (if no such position exists, returns haystack advanced to termination).

assert(find("hello, world", "World").empty);
assert(find("hello, world", "wo") == "world");
assert(find([1, 2, 3, 4], SList!(2, 3)[]) == [2, 3, 4]);

Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles);
struct BoyerMooreFinder(alias pred, Range);
BoyerMooreFinder!(binaryFun!(pred), Range) boyerMooreFinder(alias pred = "a == b", Range)(Range needle);
Finds two or more needles into a haystack. The predicate pred is used throughout to compare elements. By default, elements are compared for equality.

Parameters:
haystack | The target of the search. Must be an input range. If any of needles is a range with elements comparable to elements in haystack, then haystack must be a forward range such that the search can backtrack.
needles | One or more items to search for. Each of needles must be either comparable to one element in haystack, or be itself a forward range with elements comparable with elements in haystack.

Returns:
A tuple containing haystack positioned to match one of the needles and also the 1-based index of the matching element in needles (0 if none of needles matched, 1 if needles[0] matched, 2 if 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 "a" and 'a'), then the left-most of them in the argument list matches).

The relationship between haystack and needles simply means that one can e.g. search for individual ints or arrays of ints in an array of ints. In addition, if elements are individually comparable, searches of heterogeneous types are allowed as well: a double[] can be searched for an int or a short[], and conversely a long can be searched for a float or a double[]. This makes for efficient searches without the need to coerce one side of the comparison into the other's side type.

Example:
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, [ 1 ]) == tuple([ 2, 3 ], 3));

The complexity of the search is Ο(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 haystack as few times as possible.

Range find(alias pred, Range)(Range haystack);
Advances the input range haystack by calling haystack.popFront until either pred(haystack.front), or haystack.empty. Performs Ο(haystack.length) evaluations of pred. See also STL's find_if.

To find the last element of a bidirectional haystack satisfying pred, call find!(pred)(retro(haystack)). See also std.range.retro.

Example:
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);

bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle);
If needle occurs in haystack, positions haystack right after the first occurrence of needle and returns true. Otherwise, leaves haystack as is and returns false.

Example:
string s = "abcdef";
assert(findSkip(s, "cd") && s == "ef");
s = "abcdef";
assert(!findSkip(s, "cxd") && s == "abcdef");
assert(findSkip(s, "def") && s.empty);

auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
These functions find the first occurrence of needle in haystack and then split haystack as follows.

findSplit returns a tuple result containing 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 std.range.takeExactly.

Example:
auto a = "Carl Sagan Memorial Station";
auto r = findSplit(a, "Velikovsky");
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[0] == "Carl ", r1[0]);
assert(r1[1] == "Sagan Memorial Station");
auto r2 = findSplitAfter(a, "Sagan");
assert(r2[0] == "Carl Sagan");
assert(r2[1] == " Memorial Station");

ptrdiff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
ptrdiff_t countUntil(alias pred = "a == b", R, N)(R haystack, N needle);
Returns the number of elements which must be popped from the front of haystack before reaching an element for which startsWith!pred(haystack, needle) is true. If startsWith!pred(haystack, needle) is not true for any element in haystack, then -1 is returned.

needle may be either an element or a range.

Examples:
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);

ptrdiff_t countUntil(alias pred, R)(R haystack);
Returns the number of elements which must be popped from haystack before pred(haystack.front) is true.

Examples:
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);

ptrdiff_t indexOf(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
Deprecated. It will be removed in January 2013. Currently defaults to countUntil instead.

Not to be confused with its homonym function in std.string.

Please use std.string.indexOf if you wish to find the index of a character in a string.

Otherwise, please use std.string.countUntil to find an element's logical position in a range.

Example:
 assert(std.string.indexOf("日本語", '本') == 3);
 assert(std.algorithm.countUntil("日本語", '本') == 1);

enum OpenRight;
Interval option specifier for until (below) and others.

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));
Until!(pred, Range, Sentinel) until(alias pred = "a == b", Range, Sentinel)(Range range, Sentinel sentinel, OpenRight openRight = OpenRight.yes);
Until!(pred, Range, void) until(alias pred, Range)(Range range, OpenRight openRight = OpenRight.yes);
Lazily iterates range until value sentinel is found, at which point it stops.

Example:
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][]));

uint startsWith(alias pred = "a == b", Range, Ranges...)(Range doesThisStart, Ranges withOneOfThese);
bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis);
bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis);
If the range doesThisStart starts with any of the withOneOfThese ranges or elements, returns 1 if it starts with withOneOfThese[0], 2 if it starts with withOneOfThese[1], and so on. If none match, returns 0. In the case where doesThisStart starts with multiple of the ranges or elements in withOneOfThese, then the shortest one matches (if there are two which match which are of the same length (e.g. "a" and 'a'), then the left-most of them in the argument list matches).

Example:
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);

bool skipOver(alias pred = "a == b", R1, R2)(ref R1 r1, R2 r2);
If startsWith(r1, r2), consume the corresponding elements off r1 and return true. Otherwise, leave r1 unchanged and return false.

bool skipOver(alias pred = "a == b", R, E)(ref R r, E e);
Checks whether a range starts with an element, and if so, consume that element off r and return true. Otherwise, leave r unchanged and return false.

uint endsWith(alias pred = "a == b", Range, Ranges...)(Range doesThisEnd, Ranges withOneOfThese);
bool endsWith(alias pred = "a == b", R1, R2)(R1 doesThisEnd, R2 withThis);
bool endsWith(alias pred = "a == b", R, E)(R doesThisEnd, E withThis);
The reciprocal of startsWith.

Example:
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);

auto commonPrefix(alias pred = "a == b", R1, R2)(R1 r1, R2 r2);
Returns the common prefix of two ranges. Example:

assert(commonPrefix("hello, world", "hello, there") == "hello, ");

The type of the result is the same as takeExactly(r1, n), where n is the number of elements that both ranges start with.

Range findAdjacent(alias pred = "a == b", Range)(Range r);
Advances r until it finds the first two adjacent elements a, b that satisfy pred(a, b). Performs Ο(r.length) evaluations of pred. See also STL's adjacent_find.

Example:
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 ]);
p = findAdjacent!("a < b")(a);
assert(p == [ 7, 8, 9 ]);

Range1 findAmong(alias pred = "a == b", Range1, Range2)(Range1 seq, Range2 choices);
Advances seq by calling seq.popFront until either find!(pred)(choices, seq.front) is true, or seq becomes empty. Performs Ο(seq.length * choices.length) evaluations of pred. See also STL's find_first_of.

Example:
int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
int[] b = [ 3, 1, 2 ];
assert(findAmong(a, b) == a[2 .. $]);

size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle);
size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
size_t count(alias pred = "true", R)(R haystack);
The first version counts the number of elements x in r for which pred(x, value) is true. pred defaults to equality. Performs Ο(r.length) evaluations of pred.

The second version returns the number of times needle occurs in haystack. Throws an exception if needle.empty, as the count of the empty range in any range would be infinite. Overlapped counts are not considered, for example count("aaa", "aa") is 1, not 2.

The third version counts the elements for which pred(x) is true. Performs Ο(r.length) evaluations of pred.

Note:
Regardless of the overload, count will not accept infinite ranges for haystack.

Example:
// 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!"std.uni.toLower(a) == std.uni.toLower(b)"("AbcAdFaBf", "ab") == 2);
// count predicate in range
assert(count!("a > 1")(a) == 8);

bool balancedParens(Range, E)(Range r, E lPar, E rPar, size_t maxNestingLevel = size_t.max);
Checks whether r has "balanced parentheses", i.e. all instances of lPar are closed by corresponding instances of rPar. The parameter maxNestingLevel controls the nesting level allowed. The most common uses are the default or 0. In the latter case, no nesting is allowed.

Example:
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, '(', ')', 1));
s = "1 + (2 * 3 + 1) / (2 - 5)";
assert(balancedParens(s, '(', ')', 1));

bool equal(Range1, Range2)(Range1 r1, Range2 r2);
bool equal(alias pred, Range1, Range2)(Range1 r1, Range2 r2);
Returns true if and only if the two ranges compare equal element for element, according to binary predicate pred. The ranges may have different element types, as long as pred(a, b) evaluates to bool for a in r1 and b in r2. Performs Ο(min(r1.length, r2.length)) evaluations of pred. See also STL's equal.

Example:
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));

int cmp(alias pred = "a < b", R1, R2)(R1 r1, R2 r2);
Performs three-way lexicographical comparison on two input ranges according to predicate pred. Iterating r1 and r2 in lockstep, cmp compares each element e1 of r1 with the corresponding element e2 in r2. If binaryFun!pred(e1, e2), cmp returns a negative value. If binaryFun!pred(e2, e1), cmp returns a positive value. If one of the ranges has been finished, cmp returns a negative value if r1 has fewer elements than r2, a positive value if r1 has more elements than r2, and 0 if the ranges have the same number of elements.

If the ranges are strings, cmp performs UTF decoding appropriately and compares the ranges one code point at a time.

MinType!(T1, T2, T) min(T1, T2, T...)(T1 a, T2 b, T xs);
Returns the minimum of the passed-in values. The type of the result is computed by using std.traits.CommonType.

MaxType!(T1, T2, T) max(T1, T2, T...)(T1 a, T2 b, T xs);
Returns the maximum of the passed-in values. The type of the result is computed by using std.traits.CommonType.

Example:
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);

Tuple!(ElementType!(Range), size_t) minCount(alias pred = "a < b", Range)(Range range);
Returns the minimum element of a range together with the number of occurrences. The function can actually be used for counting the maximum or any other ordering predicate (that's why maxCount is not provided).

Example:
int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
// Minimum is 1 and occurs 3 times
assert(minCount(a) == tuple(1, 3));
// Maximum is 4 and occurs 2 times
assert(minCount!("a > b")(a) == tuple(4, 2));

Range minPos(alias pred = "a < b", Range)(Range range);
Returns the position of the minimum element of forward range range, i.e. a subrange of range starting at the position of its smallest element and with the same ending as range. The function can actually be used for counting the maximum or any other ordering predicate (that's why maxPos is not provided).

Example:
int[] 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 2
assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]);

Tuple!(Range1, Range2) mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2);
Sequentially compares elements in r1 and r2 in lockstep, and stops at the first mismatch (according to pred, by default equality). Returns a tuple with the reduced ranges that start with the two mismatched values. Performs Ο(min(r1.length, r2.length)) evaluations of pred. See also STL's mismatch.

Example:
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 .. $]);

enum EditOp;
Encodes edit operations necessary to transform one sequence into another. Given sequences s (source) and t (target), a sequence of EditOp encodes the steps that need to be taken to convert s into t. For example, if s = "cat" and "cars", the minimal sequence that transforms s into 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.

none
Current items are equal; no editing is necessary.

substitute
Substitute current item in target with current item in source.

insert
Insert current item from the source into the target.

remove
Remove current item from the target.

size_t levenshteinDistance(alias equals = "a == b", Range1, Range2)(Range1 s, Range2 t);
Returns the Levenshtein distance between s and t. The Levenshtein distance computes the minimal amount of edit operations necessary to transform s into t. Performs Ο(s.length * t.length) evaluations of equals and occupies Ο(s.length * t.length) storage.

Example:
assert(levenshteinDistance("cat", "rat") == 1);
assert(levenshteinDistance("parks", "spark") == 2);
assert(levenshteinDistance("kitten", "sitting") == 3);
// ignore case
assert(levenshteinDistance!("std.uni.toUpper(a) == std.uni.toUpper(b)")
    ("parks", "SPARK") == 2);

Tuple!(size_t, EditOp[]) levenshteinDistanceAndPath(alias equals = "a == b", Range1, Range2)(Range1 s, Range2 t);
Returns the Levenshtein distance and the edit path between s and t.

Example:
string a = "Saturday", b = "Sunday";
auto p = levenshteinDistanceAndPath(a, b);
assert(p[0] == 3);
assert(equal(p[1], "nrrnsnnn"));

Range2 copy(Range1, Range2)(Range1 source, Range2 target);
Copies the content of source into target and returns the remaining (unfilled) part of target. See also STL's copy. If a behavior similar to STL's copy_backward is needed, use copy(retro(source), retro(target)). See also std.range.retro.

Example:
int[] a = [ 1, 5 ];
int[] b = [ 9, 8 ];
int[] c = new int[a.length + b.length + 10];
auto d = copy(b, copy(a, c));
assert(c[0 .. a.length + b.length] == a ~ b);
assert(d.length == 10);

As long as the target range elements support assignment from source range elements, different types of ranges are accepted.

Example:
float[] a = [ 1.0f, 5 ];
double[] b = new double[a.length];
auto d = copy(a, b);

To copy at most n elements from range a to range b, you may want to use copy(take(a, n), b). To copy those elements from range a that satisfy predicate pred to range b, you may want to use copy(filter!(pred)(a), b).

Example:
int[] a = [ 1, 5, 8, 9, 10, 1, 2, 0 ];
auto b = new int[a.length];
auto c = copy(filter!("(a & 1) == 1")(a), b);
assert(b[0 .. $ - c.length] == [ 1, 5, 9, 1 ]);

Tuple!(Range1, Range2) swapRanges(Range1, Range2)(Range1 r1, Range2 r2);
Swaps all elements of r1 with successive elements in r2. Returns a tuple containing the remainder portions of r1 and 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.

Example:
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 ]);

void reverse(Range)(Range r);
void reverse(Range)(Range r);
Reverses r in-place. Performs r.length / 2 evaluations of swap. See also STL's reverse.

Example:
int[] arr = [ 1, 2, 3 ];
reverse(arr);
assert(arr == [ 3, 2, 1 ]);

void reverse(Char)(Char[] s);
Reverses r in-place, where r is a narrow string (having elements of type char or wchar). UTF sequences consisting of multiple code units are preserved properly.

Example:
char[] arr = "hello\U00010143\u0100\U00010143".dup;
reverse(arr);
assert(arr == "\U00010143\u0100\U00010143olleh");

size_t bringToFront(Range1, Range2)(Range1 front, Range2 back);
The 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.

bringToFront takes two ranges front and back, which may be of different types. Considering the concatenation of front and back one unified range, bringToFront rotates that unified range such that all elements in back are brought to the beginning of the unified range. The relative ordering of elements in front and back, respectively, remains unchanged.

The simplest use of bringToFront is for rotating elements in a buffer. For example:

auto arr = [4, 5, 6, 7, 1, 2, 3];
bringToFront(arr[0 .. 4], arr[4 .. $]);
assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]);

The front range may actually "step over" the back range. This is very useful with forward ranges that cannot compute comfortably right-bounded subranges like arr[0 .. 4] above. In the example below, r2 is a right subrange of r1.

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:

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 ]));

Performs Ο(max(front.length, back.length)) evaluations of swap. See also STL's rotate.

Preconditions:
Either front and back are disjoint, or back is reachable from front and front is not reachable from back.

Returns:
The number of elements brought to the front, i.e., the length of back.

enum 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 [ "abc", "b", "aBc" ] according to toUpper(a) < toUpper(b). That algorithm might choose to swap the two equivalent strings "abc" and "aBc". That does not affect the sorting since both [ "abc", "aBc", "b" ] and [ "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 [ "abc", "aBc", "b" ] would be the correct result). Such algorithms are called stable. If the ordering algorithm may swap equivalent elements discretionarily, the ordering is called 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 semistable.

Generally, the stable ordering strategy may be more costly in time and/or space than the other two because it imposes additional constraints. Similarly, semistable may be costlier than unstable. As (semi-)stability is not needed very often, the ordering algorithms in this module parameterized by SwapStrategy all choose SwapStrategy.unstable as the default.

unstable
Allows freely swapping of elements as long as the output satisfies the algorithm's requirements.

semistable
In algorithms partitioning ranges in two, preserve relative ordering of elements only to the left of the partition point.

stable
Preserve the relative ordering of elements to the largest extent allowed by the algorithm's requirements.

Range remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset);
Eliminates elements at given offsets from 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 1 is removed and remove returns the range smaller by one element. The original array has remained of the same length because all functions in std.algorithm only change content, not topology. The value 8 is repeated because std.algorithm.move was invoked to move elements around and on integers move simply copies the source to the destination. To replace a with the effect of the removal, simply assign 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 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 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, 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. tuple(3, 5) means indices 3 and 4 but not 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 SwapStrategy.unstable to remove.

int[] a = [ 0, 1, 2, 3 ];
assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);

In the case above, the element at slot 1 is removed, but replaced with the last element of the range. Taking advantage of the relaxation of the stability requirement, 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 remove works on any forward range. The moving strategy is (listed from fastest to slowest):
  • If s == SwapStrategy.unstable && isRandomAccessRange!Range && hasLength!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.
  • Otherwise, if s == SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range, then elements are still moved from the end of the range, but time is spent on advancing between slots by repeated calls to range.popFront.
  • Otherwise, elements are moved incrementally towards the front of range; a given element is never moved several times, but more elements are moved than in the previous cases.

Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range);
Reduces the length of the bidirectional range range by removing elements that satisfy pred. If s = SwapStrategy.unstable, elements are moved from the right end of the range over the elements to eliminate. If s = SwapStrategy.stable (the default), elements are moved progressively to front such that their relative order is preserved. Returns the filtered range.

Example:
int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
assert(remove!("a == 2")(a) == [ 1, 3, 3, 4, 5, 5, 6 ]);

Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Partitions a range in two using pred as a predicate. Specifically, reorders the range r = [left, right) using swap such that all elements i for which pred(i) is true come before all elements j for which pred(j) returns false.

Performs Ο(r.length) (if unstable or semistable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap. The unstable version computes the minimum possible evaluations of swap (roughly half of those performed by the semistable version).

See also STL's partition and stable_partition.

Returns:
The right part of r after partitioning.

If ss == SwapStrategy.stable, partition preserves the relative ordering of all elements a, b in r for which pred(a) == pred(b). If ss == SwapStrategy.semistable, partition preserves the relative ordering of all elements a, b in the left part of r for which pred(a) == pred(b).

Example:
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 .. $]);

bool isPartitioned(alias pred, Range)(Range r);
Returns true if r is partitioned according to predicate pred.

Example:
int[] r = [ 1, 3, 5, 7, 8, 2, 4, ];
assert(isPartitioned!("a & 1")(r));

auto partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)(Range r, E pivot);
Rearranges elements in r in three adjacent ranges and returns them. The first and leftmost range only contains elements in r less than pivot. The second and middle range only contains elements in r that are equal to pivot. Finally, the third and rightmost range only contains elements in r that are greater than pivot. The less-than test is defined by the binary function less.

Example:
auto a = [ 8, 3, 4, 1, 4, 7, 4 ];
auto pieces = partition3(a, 4);
assert(a == [ 1, 3, 4, 4, 4, 7, 8 ]);
assert(pieces[0] == [ 1, 3 ]);
assert(pieces[1] == [ 4, 4, 4 ]);
assert(pieces[2] == [ 7, 8 ]);

BUGS:
stable partition3 has not been implemented yet.

void topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t nth);
Reorders the range r using swap such that r[nth] refers to the element that would fall there if the range were fully sorted. In addition, it also partitions r such that all elements e1 from r[0] to r[nth] satisfy !less(r[nth], e1), and all elements e2 from r[nth] to r[r.length] satisfy !less(e2, r[nth]). Effectively, it finds the nth smallest (according to less) elements in r. Performs Ο(r.length) (if unstable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap. See also STL's nth_element.

Example:
int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
auto n = 4;
topN!(less)(v, n);
assert(v[n] == 9);
// Equivalent form:
topN!("a < b")(v, n);
assert(v[n] == 9);

BUGS:
Stable topN has not been implemented yet.

void topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1 r1, Range2 r2);
Stores the smallest elements of the two ranges in the left-hand range.

SortedRange!(Range, less) sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Sorts a random-access range according to the predicate less. Performs Ο(r.length * log(r.length)) (if unstable) or Ο(r.length * log(r.length) * log(r.length)) (if stable) evaluations of less and swap. See also STL's sort and stable_sort.

sort returns a std.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 std.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 can know that std.range.SortedRange has been sorted.

See Also:
std.range.assumeSorted

Remark:
Stable sort is implementated as Timsort, the original code at XSort by Xinok, public domain.

Example:
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) { return x > y; }
sort!(myComp)(array);
assert(array == [ 4, 3, 2, 1 ]);
// 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" ]);

template multiSort(less...)
void multiSort(Range)(Range r) if (validPredicates!(ElementType!Range, less));

Sorts a range by multiple keys. The call multiSort!("a.id < b.id", "a.date > b.date")(r) sorts the range r by id ascending, and sorts elements that have the same id by date descending. Such a call is equivalent to sort!"a.id != b.id ? a.id < b.id : a.date > b.date"(r), but multiSort is faster because it does fewer comparisons (in addition to being more convenient).

Example:
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);

void schwartzSort(alias transform, alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Sorts a range using an algorithm akin to the Schwartzian transform, also known as the decorate-sort-undecorate pattern in Python and Lisp. (Not to be confused with the other Schwartz.) This function is helpful when the sort comparison includes an expensive computation. 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!("hashFun(a) < hashFun(b)")(array);
// Sort strings by hash, fast (only computes arr.length hashes):
schwartzSort!(hashFun, "a < b")(array);

The 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 schwartzIsSorted is not provided because the effect can be achieved by calling isSorted!less(map!transform(r)).

void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t n);
Reorders the random-access range r such that the range r[0 .. mid] is the same as if the entire r were sorted, and leaves the range r[mid .. r.length] in no particular order. Performs Ο(r.length * log(mid)) evaluations of pred. The implementation simply calls topN!(less, ss)(r, n) and then sort!(less, ss)(r[0 .. n]).

Example:
int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
partialSort(a, 5);
assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);

void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(SortedRange!(Range1, less) lhs, Range2 rhs);
Sorts the random-access range chain(lhs, rhs) according to predicate less. The left-hand side of the range lhs is assumed to be already sorted; rhs is assumed to be unsorted. The exact strategy chosen depends on the relative sizes of lhs and rhs. Performs Ο(lhs.length + rhs.length * log(rhs.length)) (best case) to Ο((lhs.length + rhs.length) * log(lhs.length + rhs.length)) (worst-case) evaluations of swap.

Example:
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 ]);

bool isSorted(alias less = "a < b", Range)(Range r);
Checks whether a forward range is sorted according to the comparison operation less. Performs Ο(r.length) evaluations of less.

Example:
int[] arr = [4, 3, 2, 1];
assert(!isSorted(arr));
sort(arr);
assert(isSorted(arr));
sort!("a > b")(arr);
assert(isSorted!("a > b")(arr));

void makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index);
void makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index);
Computes an index for r based on the comparison 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 sort's.

makeIndex overwrites its second argument with the result, but never reallocates it. If the second argument's length is less than that of the range indexed, an exception is thrown.

The first overload of makeIndex writes to a range containing pointers, and the second writes to a range containing offsets. The first overload requires Range to be a forward range, and the latter requires it to be a random-access range.

Example:
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));

enum SortOutput;
Specifies whether the output of certain algorithm is desired in sorted format.

no
Don't sort output

yes
Sort output

bool canFind(alias pred = "a == b", R, E)(R haystack, E needle);
Returns true if and only if value can be found in range. Performs Ο(needle.length) evaluations of pred.

size_t canFind(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles);
Returns the 1-based index of the first needle found in haystack. If no needle is found, then 0 is returned.

So, if used directly in the condition of an if statement or loop, the result will be true if one of the needles is found and false if none are found, whereas if the result is used elsewhere, it can either be cast to bool for the same effect or used to get which needle was found first without having to deal with the tuple that LREF find returns for the same operation.

bool any(alias pred, Range)(Range range);
Returns true if and only if a value v satisfying the predicate pred can be found in the forward range range. Performs Ο(r.length) evaluations of pred.

bool all(alias pred, R)(R range);
Returns true if and only if all values in range satisfy the predicate pred. Performs Ο(r.length) evaluations of pred.

Examples:
assert(all!"a & 1"([1, 3, 5, 7, 9]));
assert(!all!"a & 1"([1, 2, 3, 5, 7, 9]));

TRange topNCopy(alias less = "a < b", SRange, TRange)(SRange source, TRange target, SortOutput sorted = SortOutput.no);
Copies the top n elements of the input range source into the random-access range target, where n = target.length. Elements of source are not touched. If sorted is true, the target is sorted. Otherwise, the target respects the heap property.

Example:
int[] a = [ 10, 16, 2, 3, 1, 5, 0 ];
int[] b = new int[3];
topNCopy(a, b, true);
assert(b == [ 0, 1, 2 ]);

struct SetUnion(alias less = "a < b", Rs...) if (allSatisfy!(isInputRange, Rs));
SetUnion!(less, Rs) setUnion(alias less = "a < b", Rs...)(Rs rs);
Lazily computes the union of two or more ranges rs. The ranges are assumed to be sorted by less. Elements in the output are not unique; the length of the output is the sum of the lengths of the inputs. (The length member is offered if all ranges also have length.) The element types of all ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
int[] c = [ 10 ];
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][]));

struct SetIntersection(alias less = "a < b", Rs...) if (allSatisfy!(isInputRange, Rs));
SetIntersection!(less, Rs) setIntersection(alias less = "a < b", Rs...)(Rs ranges);
Lazily computes the intersection of two or more input ranges rs. The ranges are assumed to be sorted by less. The element types of all ranges must have a common type.

Example:
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][]));

struct SetDifference(alias less = "a < b", R1, R2) if (isInputRange!(R1) && isInputRange!(R2));
SetDifference!(less, R1, R2) setDifference(alias less = "a < b", R1, R2)(R1 r1, R2 r2);
Lazily computes the difference of r1 and r2. The two ranges are assumed to be sorted by less. The element types of the two ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
assert(equal(setDifference(a, b), [5, 9][]));

struct SetSymmetricDifference(alias less = "a < b", R1, R2) if (isInputRange!(R1) && isInputRange!(R2));
SetSymmetricDifference!(less, R1, R2) setSymmetricDifference(alias less = "a < b", R1, R2)(R1 r1, R2 r2);
Lazily computes the symmetric difference of r1 and r2, i.e. the elements that are present in exactly one of r1 and r2. The two ranges are assumed to be sorted by less, and the output is also sorted by less. The element types of the two ranges must have a common type.

Example:
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][]));

struct NWayUnion(alias less, RangeOfRanges);
NWayUnion!(less, RangeOfRanges) nWayUnion(alias less = "a < b", RangeOfRanges)(RangeOfRanges ror);
Computes the union of multiple sets. The input sets are passed as a range of ranges and each is assumed to be sorted by less. Computation is done lazily, one union element at a time. The complexity of one popFront operation is Ο(log(ror.length)). However, the length of ror decreases as ranges in it are exhausted, so the complexity of a full pass through NWayUnion is dependent on the distribution of the lengths of ranges contained within ror. If all ranges have the same length n (worst case scenario), the complexity of a full pass through NWayUnion is Ο(n * ror.length * log(ror.length)), i.e., log(ror.length) times worse than just spanning all ranges in turn. The output comes sorted (unstably) by less.

Warning:
Because NWayUnion does not allocate extra memory, it will leave ror modified. Namely, NWayUnion assumes ownership of ror and discretionarily swaps and advances elements of it. If you want ror to preserve its contents after the call, you may want to pass a duplicate to NWayUnion (and perhaps cache the duplicate in between calls).

Example:
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[]));

void largestPartialIntersection(alias less = "a < b", RangeOfRanges, Range)(RangeOfRanges ror, Range tgt, SortOutput sorted = SortOutput.no);
Given a range of sorted forward ranges ror, copies to tgt the elements that are common to most ranges, along with their number of occurrences. All ranges in ror are assumed to be sorted by less. Only the most frequent tgt.length elements are returned.

Example:
// 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];
largestPartialIntersection(a, b);
// First member is the item, second is the occurrence count
assert(b[0] == tuple(7.0, 4u));

7.0 is the correct answer because it occurs in 4 out of the 5 inputs, more than any other number. The second member of the resulting tuple is indeed 4 (recording the number of occurrences of 7.0). If more of the top-frequent numbers are needed, just create a larger tgt range. In the axample above, creating b with length 2 yields tuple(1.0, 3u) in the second position.

The function largestPartialIntersection is useful for e.g. searching an inverted index for the documents most likely to contain some terms of interest. The complexity of the search is Ο(n * log(tgt.length)), where 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 (largestPartialIntersection builds its result directly in tgt and requires no extra memory).

Warning:
Because largestPartialIntersection does not allocate extra memory, it will leave ror modified. Namely, largestPartialIntersection assumes ownership of ror and discretionarily swaps and advances elements of it. If you want ror to preserve its contents after the call, you may want to pass a duplicate to largestPartialIntersection (and perhaps cache the duplicate in between calls).

void largestPartialIntersectionWeighted(alias less = "a < b", RangeOfRanges, Range, WeightsAA)(RangeOfRanges ror, Range tgt, WeightsAA weights, SortOutput sorted = SortOutput.no);
Similar to largestPartialIntersection, but associates a weight with each distinct element in the intersection.

Example:
// 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));

The correct answer in this case is 4.0, which, although only appears two times, has a total weight 4.6 (three times its weight 2.3). The value 7 is weighted with 1.1 and occurs four times for a total weight 4.4.

Andrei Alexandrescu 2008-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.array

Functions and types that manipulate built-in arrays.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu and Jonathan M Davis

Source:
std/array.d

ForeachType!(Range)[] array(Range)(Range r);
Returns a newly-allocated dynamic array consisting of a copy of the input range, static array, dynamic array, or class or struct with an opApply function r. Note that narrow strings are handled as a special case in an overload.

Example:
auto a = array([1, 2, 3, 4, 5][]);
assert(a == [ 1, 2, 3, 4, 5 ]);
Standard input
Command line arguments
Application output

ElementType!(String)[] array(String)(String str);
Convert a narrow string to an array type that fully supports random access. This is handled as a special case and always returns a dchar[], const(dchar)[], or immutable(dchar)[] depending on the constness of the input.

auto assocArray(Range)(Range r);
Returns a newly allocated associative array out of elements of the input range, which must be a range of tuples (Key, Value).

Example:
auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"]));
assert(a == [0:"a", 1:"b", 2:"c"]);
auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]);
assert(b == ["foo":"bar", "baz":"quux"]);
Standard input
Command line arguments
Application output

auto uninitializedArray(T, I...)(I sizes);
Returns a new array of type T allocated on the garbage collected heap without initializing its elements. This can be a useful optimization if every element will be immediately initialized. T may be a multidimensional array. In this case sizes may be specified for any number of dimensions from 1 to the number in T.

Examples:
double[] arr = uninitializedArray!(double[])(100);
assert(arr.length == 100);

double[][] matrix = uninitializedArray!(double[][])(42, 31);
assert(matrix.length == 42);
assert(matrix[0].length == 31);
Standard input
Command line arguments
Application output

@trusted auto minimallyInitializedArray(T, I...)(I sizes);
Returns a new array of type T allocated on the garbage collected heap. Initialization is guaranteed only for pointers, references and slices, for preservation of memory safety.

pure nothrow @safe bool empty(T)(in T[] a);
Implements the range interface primitive empty for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.empty is equivalent to empty(array).

Example:
auto a = [ 1, 2, 3 ];
assert(!a.empty);
assert(a[3 .. $].empty);
Standard input
Command line arguments
Application output

pure nothrow @safe T[] save(T)(T[] a);
Implements the range interface primitive save for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.save is equivalent to save(array). The function does not duplicate the content of the array, it simply returns its argument.

Example:
auto a = [ 1, 2, 3 ];
auto b = a.save;
assert(b is a);
Standard input
Command line arguments
Application output

void popFront(A)(ref A a);
Implements the range interface primitive popFront for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.popFront is equivalent to popFront(array). For narrow strings, popFront automaticaly advances to the next code point.

Example:
int[] a = [ 1, 2, 3 ];
a.popFront();
assert(a == [ 2, 3 ]);
Standard input
Command line arguments
Application output

void popBack(A)(ref A a);
Implements the range interface primitive popBack for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.popBack is equivalent to popBack(array). For narrow strings, popFront automaticaly eliminates the last code point.

Example:
int[] a = [ 1, 2, 3 ];
a.popBack();
assert(a == [ 1, 2 ]);
Standard input
Command line arguments
Application output

T front(T)(T[] a);
Implements the range interface primitive front for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.front is equivalent to front(array). For narrow strings, front automaticaly returns the first code point as a dchar.

Example:
int[] a = [ 1, 2, 3 ];
assert(a.front == 1);
Standard input
Command line arguments
Application output

T back(T)(T[] a);
Implements the range interface primitive back for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.back is equivalent to back(array). For narrow strings, back automaticaly returns the last code point as a dchar.

Example:
int[] a = [ 1, 2, 3 ];
assert(a.back == 3);
Standard input
Command line arguments
Application output

void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff);
void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff);
Inserts stuff (which must be an input range or any number of implicitly convertible items) in array at position pos.

Example:
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]);
Standard input
Command line arguments
Application output

bool sameHead(T)(T[] lhs, T[] rhs);
Returns whether the fronts of lhs and rhs both refer to the same place in memory, making one of the arrays a slice of the other which starts at index 0.

bool sameTail(T)(T[] lhs, T[] rhs);
Returns whether the backs of lhs and rhs both refer to the same place in memory, making one of the arrays a slice of the other which end at index $.

ElementEncodingType!(S)[] replicate(S)(S s, size_t n);
Returns an array that consists of s (which must be an input range) repeated n times. This function allocates, fills, and returns a new array. For a lazy version, refer to std.range.repeat.

S[] split(S)(S s);
Split the string s into an array of words, using whitespace as delimiter. Runs of whitespace are merged together (no empty words are produced).

auto splitter(C)(C[] s);
Splits a string by whitespace.

Example:
auto a = " a     bcd   ef gh ";
assert(equal(splitter(a), ["", "a", "bcd", "ef", "gh"][]));
Standard input
Command line arguments
Application output

Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim);
Splits s into an array, using delim as the delimiter.

ElementEncodingType!(ElementType!(RoR))[] join(RoR, R)(RoR ror, R sep);
ElementEncodingType!(ElementType!(RoR))[] join(RoR)(RoR ror);
Concatenates all of the ranges in ror together into one array using sep as the separator if present.

Examples:
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]);
Standard input
Command line arguments
Application output

E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to);
Replace occurrences of from with to in subject. Returns a new array without changing the contents of subject, or the original array if no match is found.

void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to);
Same as above, but outputs the result via OutputRange sink. If no match is found the original array is transfered to sink as is.

void replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff);
Replaces elements from array with indices ranging from from (inclusive) to to (exclusive) with the range stuff. Expands or shrinks the array as needed.

Example:
int[] a = [ 1, 2, 3, 4 ];
a.replaceInPlace(1, 3, [ 9, 9, 9 ]);
assert(a == [ 1, 9, 9, 9, 4 ]);
Standard input
Command line arguments
Application output

E[] replaceFirst(E, R1, R2)(E[] subject, R1 from, R2 to);
Replaces the first occurrence of from with to in a. Returns a new array without changing the contents of subject, or the original array if no match is found.

inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement);
Returns an array that is s with slice replaced by replacement[].

struct Appender(A : T[], T);
Implements an output range that appends data to an array. This is recommended over a ~= data when appending many elements because it is more efficient.

Example:
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 ]);
Standard input
Command line arguments
Application output

this(T[] arr);
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.

void reserve(size_t newCapacity);
Reserve at least newCapacity elements for appending. Note that more elements may be reserved than requested. If newCapacity < capacity, then nothing is done.

const size_t capacity();
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, capacity returns 0.

inout inout(T)[] data();
Returns the managed array.

void put(U)(U item);
Appends one item to the managed array.

void put(Range)(Range items);
Appends an entire range to the managed array.

void clear();
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 Appender might overwrite immutable data.

void shrinkTo(size_t newlength);
Shrinks the managed array to the given length. Passing in a length that's greater than the current array length throws an enforce exception.

struct RefAppender(A : T[], T);
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.

this(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. 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.

const size_t capacity();
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, capacity returns 0.

inout inout(T)[] data();
Returns the managed array.

Appender!(E[]) appender(A : E[], E)(A array = null);
Convenience function that returns an Appender!(A) object initialized with array.

RefAppender!(E[]) appender(A : E[]*, E)(A array);
Convenience function that returns a RefAppender!(A) object initialized with array. Don't use null for the array pointer, use the other version of appender instead.

Copyright Andrei Alexandrescu 2008- and Jonathan M Davis 2011-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.ascii

Functions which operate on ASCII characters.

All of the functions in std.ascii accept unicode characters but effectively ignore them. All isX functions return false for unicode characters, and all toX functions do nothing to unicode characters.

For functions which operate on unicode characters, see std.uni.

References:
ASCII Table, Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright and Jonathan M Davis

Source:
std/ascii.d

immutable string hexDigits;
0..9A..F

immutable string fullHexDigits;
0..9A..Fa..f

immutable string digits;
0..9

immutable string octalDigits;
0..7

immutable string lowercase;
a..z

immutable string letters;
A..Za..z

immutable string uppercase;
A..Z

immutable string whitespace;
ASCII whitespace

immutable string newline;
Newline sequence for this system.

pure nothrow @safe bool isAlphaNum(dchar c);
Returns whether c is a letter or a number (0..9, a..z, A..Z).

pure nothrow @safe bool isAlpha(dchar c);
Returns whether c is an ASCII letter (A..Z, a..z).

pure nothrow @safe bool isLower(dchar c);
Returns whether c is a lowercase ASCII letter (a..z).

pure nothrow @safe bool isUpper(dchar c);
Returns whether c is an uppercase ASCII letter (A..Z).

pure nothrow @safe bool isDigit(dchar c);
Returns whether c is a digit (0..9).

pure nothrow @safe bool isOctalDigit(dchar c);
Returns whether c is a digit in base 8 (0..7).

pure nothrow @safe bool isHexDigit(dchar c);
Returns whether c is a digit in base 16 (0..9, A..F, a..f).

pure nothrow @safe bool isWhite(dchar c);
Whether or not c is a whitespace character. That includes the space, tab, vertical tab, form feed, carriage return, and linefeed characters.

pure nothrow @safe bool isControl(dchar c);
Returns whether c is a control character.

pure nothrow @safe bool isPunctuation(dchar c);
Whether or not c is a punctuation character. That includes all ASCII characters which are not control characters, letters, digits, or whitespace.

pure nothrow @safe bool isGraphical(dchar c);
Whether or not c is a printable character other than the space character.

pure nothrow @safe bool isPrintable(dchar c);
Whether or not c is a printable character - including the space character.

pure nothrow @safe bool isASCII(dchar c);
Whether or not c is in the ASCII character set - i.e. in the range 0..0x7F.

pure nothrow @safe dchar toLower(dchar c);
If c is an uppercase ASCII character, then its corresponding lowercase letter is returned. Otherwise, c is returned.

pure nothrow @safe dchar toUpper(dchar c);
If c is a lowercase ASCII character, then its corresponding uppercase letter is returned. Otherwise, c is returned.

Copyright 2000 - | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.base64

Encoding / Decoding Base64 format.

Implemented according to RFC 4648 - The Base16.

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]);
Standard input
Command line arguments
Application output
Support Range interface using Encoder / Decoder.

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);
Standard input
Command line arguments
Application output

License:
Boost License 1.0.

Authors:
Masahiro Nakagawa, Daniel Murphy (Single value Encoder and Decoder)

Source:
std/base64.d

alias Base64Impl!('+', '/') Base64;
The Base64

alias Base64Impl!('-', '_') Base64URL;
The "URL and Filename safe" Base64

template Base64Impl(char Map62th, char Map63th, char Padding = '=')
Core implementation for Base64 format.

Example:
 alias Base64Impl!('+', '/')                   Base64;    // The Base64 format(Already defined).
 alias Base64Impl!('!', '=', Base64.NoPadding) Base64Re;  // non-standard Base64 format for Regular expression

NOTE:
encoded-string doesn't have padding character if set Padding parameter to NoPadding.

size_t encodeLength(in size_t sourceLength);
Calculates the minimum length for encoding.

Parameters:
size_t sourceLength the length of source array.

Returns:
the calculated length using sourceLength.

char[] encode(R1, R2)(in R1 source, R2 buffer);
char[] encode(R1, R2)(R1 source, R2 buffer);
Encodes source into buffer.

Parameters:
source | an InputRange to encode.
range | a buffer to store encoded result.

Returns:
the encoded string that slices buffer.

size_t encode(R1, R2)(in R1 source, R2 range);
size_t encode(R1, R2)(R1 source, R2 range);
Encodes source into range.

Parameters:
source | an InputRange to encode.
range | an OutputRange to put encoded result.

Returns:
the number of calling put.

char[] encode(Range)(Range source);
char[] encode(Range)(Range source);
Encodes source to new buffer.

Shortcut to encode(source, buffer) function.

struct Encoder(Range) if (isInputRange!(Range) && (is(ElementType!(Range) : const(ubyte)[]) || is(ElementType!(Range) : const(char)[])));
Range that encodes chunk data at a time.

const bool empty();
Range primitive operation that checks iteration state.

Returns:
true if there are no more elements to be iterated.

char[] front();
Range primitive operation that returns the currently iterated element.

Returns:
the encoded string.

void popFront();
Range primitive operation that advances the range to its next element.

Throws:
an Exception when you try to call popFront on empty range.

typeof(this) save();
Captures a Range state.

Returns:
a copy of this.

struct Encoder(Range) if (isInputRange!(Range) && is(ElementType!(Range) : ubyte));
Range that encodes single character at a time.

const bool empty();
Range primitive operation that checks iteration state.

Returns:
true if there are no more elements to be iterated.

ubyte front();
Range primitive operation that returns the currently iterated element.

Returns:
the encoded character.

void popFront();
Range primitive operation that advances the range to its next element.

Throws:
an Exception when you try to call popFront on empty range.

typeof(this) save();
Captures a Range state.

Returns:
a copy of this.

Encoder!(Range) encoder(Range)(Range range);
Iterates through an InputRange at a time by using Encoder.

Default Encoder encodes chunk data.

Example:
File f = File("text.txt", "r");
scope(exit) f.close();

uint line = 0;
foreach (encoded; Base64.encoder(f.byLine()))
{
    writeln(++line, ". ", encoded);
}
Standard input
Command line arguments
Application output

In addition, You can use Encoder that returns encoded single character. This Encoder performs Range-based and lazy encoding.

Example:
ubyte[] data = cast(ubyte[]) "0123456789";

 // The ElementType of data is not aggregation type
foreach (encoded; Base64.encoder(data))
{
    writeln(encoded);
}
Standard input
Command line arguments
Application output

Parameters:
range an InputRange to iterate.

Returns:
a Encoder object instantiated and initialized according to the arguments.

size_t decodeLength(in size_t sourceLength);
Calculates the minimum length for decoding.

Parameters:
size_t sourceLength the length of source array.

Returns:
calculated length using sourceLength.

ubyte[] decode(R1, R2)(in R1 source, R2 buffer);
ubyte[] decode(R1, R2)(R1 source, R2 buffer);
Decodes source into buffer.

Parameters:
source | an InputRange to decode.
buffer | a buffer to store decoded result.

Returns:
the decoded string that slices buffer.

Throws:
an Exception if source has character outside base-alphabet.

size_t decode(R1, R2)(in R1 source, R2 range);
size_t decode(R1, R2)(R1 source, R2 range);
Decodes source into range.

Parameters:
source | an InputRange to decode.
range | an OutputRange to put decoded result

Returns:
the number of calling put.

Throws:
an Exception if source has character outside base-alphabet.

ubyte[] decode(Range)(Range source);
ubyte[] decode(Range)(Range source);
Decodes source into new buffer.

Shortcut to decode(source, buffer) function.

struct Decoder(Range) if (isInputRange!(Range) && (is(ElementType!(Range) : const(char)[]) || is(ElementType!(Range) : const(ubyte)[])));
Range that decodes chunk data at a time.

const bool empty();
Range primitive operation that checks iteration state.

Returns:
true if there are no more elements to be iterated.

ubyte[] front();
Range primitive operation that returns the currently iterated element.

Returns:
the decoded result.

void popFront();
Range primitive operation that advances the range to its next element.

Throws:
an Exception when you try to call popFront on empty range.

typeof(this) save();
Captures a Range state.

Returns:
a copy of this.

struct Decoder(Range) if (isInputRange!(Range) && is(ElementType!(Range) : char));
Range that decodes single character at a time.

const bool empty();
Range primitive operation that checks iteration state.

Returns:
true if there are no more elements to be iterated.

ubyte front();
Range primitive operation that returns the currently iterated element.

Returns:
the decoded result.

void popFront();
Range primitive operation that advances the range to its next element.

Throws:
an Exception when you try to call popFront on empty range.

typeof(this) save();
Captures a Range state.

Returns:
a copy of this.

Decoder!(Range) decoder(Range)(Range range);
Iterates through an InputRange at a time by using Decoder.

Default Decoder decodes chunk data.

Example:
foreach (decoded; Base64.decoder(stdin.byLine()))
{
    writeln(decoded);
}
Standard input
Command line arguments
Application output

In addition, You can use Decoder that returns decoded single character. This Decoder performs Range-based and lazy decoding.

Example:
auto encoded = Base64.encoder(cast(ubyte[])"0123456789");
foreach (n; map!q{a - '0'}(Base64.decoder(encoded)))
{
    writeln(n);
}
Standard input
Command line arguments
Application output

NOTE:
If you use ByChunk, chunk-size should be the multiple of 4. Decoder can't judge a encode-boundary.

Parameters:
range an InputRange to iterate.

Returns:
a Decoder object instantiated and initialized according to the arguments.

Masahiro Nakagawa 2010-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.bigint

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:
  • Karatsuba multiplication
  • Squaring is optimized independently of multiplication
  • Divide-and-conquer division
  • Binary exponentiation

For very large numbers, consider using the GMP library instead.

License:
Boost License 1.0.

Authors:
Don Clugston

Source:
std/bigint.d

struct BigInt;
A struct representing an arbitrary precision integer

All arithmetic operations are supported, except unsigned shift right (>>>). Logical operations are not currently supported.

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

Example:
        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;

this(T : const(char)[])(T s);
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.

BUG:
Should throw a IllegalArgumentException/ConvError if invalid character found

this(T : long)(T x);

BigInt opAssign(T : long)(T x);

BigInt opAssign(T : BigInt)(T x);

const bool opEquals()(auto ref const BigInt y);

const bool opEquals(T : long)(T y);

int opCmp(T : long)(T y);

int opCmp(T : BigInt)(T y);

const pure long toLong();
Returns the value of this BigInt as a long, or +- long.max if outside the representable range.

const pure int toInt();
Returns the value of this BigInt as an int, or +- int.max if outside the representable range.

const pure @property size_t uintLength();
Number of significant uints which are used in storing this number. The absolute value of this BigInt is always < 2^^(32*uintLength)

const pure @property size_t ulongLength();
Number of significant ulongs which are used in storing this number. The absolute value of this BigInt is always < 2^^(64*ulongLength)

const void toString(scope void delegate(const(char)[]) sink, string formatString);
Convert the BigInt to string, passing it to 'sink'.

The output format is controlled via formatString:
The output format is controlled via formatString:
"d" | Decimal
"x" | Hexadecimal, lower case
"X" | Hexadecimal, upper case
"s" | Default formatting (same as "d")
null | Default formatting (same as "d")
"d" | Decimal
"x" | Hexadecimal, lower case
"X" | Hexadecimal, upper case
"s" | Default formatting (same as "d")
null | Default formatting (same as "d")

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.bitmanip

Bit-level manipulation facilities.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Jonathan M Davis, Alex Rønne Petersen, Damian Ziemba

Source:
std/bitmanip.d

template bitfields(T...)
Allows creating bit fields inside structs and classes.

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 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 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 bool, followed by unsigned types, followed by signed types.

struct FloatRep;
Allows manipulating the fraction, exponent, and sign parts of a 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 DoubleRep;
Allows manipulating the fraction, exponent, and sign parts of a 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 BitArray;
An array of bits.

const const @property size_t dim();
Gets the amount of native words backing this BitArray.

const const @property size_t length();
Gets the amount of bits in the BitArray.

@property size_t length(size_t newlen);
Sets the amount of bits in the BitArray.

const bool opIndex(size_t i);
Gets the i'th bit in the BitArray.

bool opIndexAssign(bool b, size_t i);
Sets the i'th bit in the BitArray.

const @property BitArray dup();
Duplicates the BitArray and its contents.

int opApply(scope int delegate(ref bool) dg);
const int opApply(scope int delegate(bool) dg);
int opApply(scope int delegate(ref uint, ref bool) dg);
const int opApply(scope int delegate(uint, bool) dg);
Support for foreach loops for BitArray.

@property BitArray reverse();
Reverses the bits of the BitArray.

@property BitArray sort();
Sorts the BitArray's elements.

const const bool opEquals(ref const BitArray a2);
Support for operators == and != for BitArray.

const int opCmp(BitArray a2);
Supports comparison operators for BitArray.

const pure nothrow size_t toHash();
Support for hashing for BitArray.

void init(bool[] ba);
Set this BitArray to the contents of ba.

void init(void[] v, size_t numbits);
Map the BitArray onto v, with numbits being the number of bits in the array. Does not copy the data.

This is the inverse of opCast.

void[] opCast(T : void[])();
Convert to void[].

size_t[] opCast(T : size_t[])();
Convert to size_t[].

BitArray opCom();
Support for unary operator ~ for BitArray.

BitArray opAnd(BitArray e2);
Support for binary operator & for BitArray.

const BitArray opOr(BitArray e2);
Support for binary operator | for BitArray.

const BitArray opXor(BitArray e2);
Support for binary operator ^ for BitArray.

const BitArray opSub(BitArray e2);
Support for binary operator - for BitArray.

a - b for BitArray means the same thing as a & ~b.

BitArray opAndAssign(BitArray e2);
Support for operator &= for BitArray.

BitArray opOrAssign(BitArray e2);
Support for operator |= for BitArray.

BitArray opXorAssign(BitArray e2);
Support for operator ^= for BitArray.

BitArray opSubAssign(BitArray e2);
Support for operator -= for BitArray.

a -= b for BitArray means the same thing as a &= ~b.

BitArray opCatAssign(bool b);
BitArray opCatAssign(BitArray b);
Support for operator ~= for BitArray.

const BitArray opCat(bool b);
const BitArray opCat_r(bool b);
const BitArray opCat(BitArray b);
Support for binary operator ~ for BitArray.

pure nothrow @safe T swapEndian(T)(T val);
Swaps the endianness of the given integral value or character.

pure nothrow @safe auto nativeToBigEndian(T)(T val);
Converts the given value from the native endianness to big endian and returns it as a ubyte[n] where n is the size of the given type.

Returning a 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).

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

Examples:
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));

pure nothrow @safe T bigEndianToNative(T, size_t n)(ubyte[n] val);
Converts the given value from big endian to the native endianness and returns it. The value is given as a ubyte[n] where 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 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).

Examples:
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));

pure nothrow @safe auto nativeToLittleEndian(T)(T val);
Converts the given value from the native endianness to little endian and returns it as a ubyte[n] where n is the size of the given type.

Returning a 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).

Examples:
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));

pure nothrow @safe T littleEndianToNative(T, size_t n)(ubyte[n] val);
Converts the given value from little endian to the native endianness and returns it. The value is given as a ubyte[n] where 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 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).

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

Examples:
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));

T peek(T, Endian endianness = Endian.bigEndian, R)(R range);
T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t index);
T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t* index);
Takes a range of ubytes and converts the first T.sizeof bytes to T. The value returned is converted from the given endianness to the native endianness. The range is not consumed.

Parems:
T = The integral type to convert the first 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 hasSlicing!R is true.

Examples:
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);

T read(T, Endian endianness = Endian.bigEndian, R)(ref R range);
Takes a range of ubytes and converts the first T.sizeof bytes to T. The value returned is converted from the given endianness to the native endianness. The T.sizeof bytes which are read are consumed from the range.

Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness that the bytes are assumed to be in. range = The range to read from.

Examples:
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);

void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t index);
void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t* index);
Takes an integral value, converts it to the given endianness, and writes it to the given range of ubytes as a sequence of T.sizeof ubytes starting at index. hasSlicing!R must be true.

Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness to write the bytes in. range = The range to write to. index = The index to start writing to. If index is a pointer, then it is updated to the index after the bytes read.

Examples:
{
    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);
}

void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value);
Takes an integral value, converts it to the given endianness, and appends it to the given range of ubytes (using put) as a sequence of T.sizeof ubytes starting at index. hasSlicing!R must be true.

Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness to write the bytes in. range = The range to append to.

Examples:
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]);

Copyright Digital Mars 2007 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.compiler

Identify the compiler used and its various features.

License:
Boost License 1.0.

Authors:
Walter Bright, Alex Rønne Petersen

Source:
std/compiler.d

immutable string name;
Vendor specific string naming the compiler, for example: "Digital Mars D".

enum Vendor;
Master list of D compiler vendors.

unknown
Compiler vendor could not be detected

digitalMars
Digital Mars D (DMD)

gnu
GNU D Compiler (GDC)

llvm
LLVM D Compiler (LDC)

dotNET
D.NET

sdc
Stupid D Compiler (SDC)

immutable Vendor vendor;
Which vendor produced this compiler.

immutable uint version_major;
immutable uint version_minor;
The vendor specific version number, as in version_major.version_minor

immutable uint D_major;
The version of the D Programming Language Specification supported by the compiler.

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.complex

This module contains the Complex type, which is used to represent complex numbers, along with related mathematical operations and functions.

Complex will eventually replace the built-in types cfloat, cdouble, creal, ifloat, idouble, and ireal.

Authors:
Lars Tandle Kyllingstad, Don Clugston

License:
Boost License 1.0

Source:
std/complex.d

pure nothrow @safe auto complex(T)(T re);
pure nothrow @safe auto complex(R, I)(R re, I im);
Helper function that returns a complex number with the specified real and imaginary parts.

If neither re nor im are floating-point numbers, this function returns a Complex!double. Otherwise, the return type is deduced using std.traits.CommonType!(R, I).

Examples:
    auto c = complex(2.0);
    static assert (is(typeof(c) == Complex!double));
    assert (c.re == 2.0);
    assert (c.im == 0.0);

    auto w = complex(2);
    static assert (is(typeof(w) == Complex!double));
    assert (w == c);

    auto z = complex(1, 3.14L);
    static assert (is(typeof(z) == Complex!real));
    assert (z.re == 1.0L);
    assert (z.im == 3.14L);

struct Complex(T) if (isFloatingPoint!(T));
A complex number parametrised by a type T, which must be either float, double or real.

T re;
The real part of the number.

T im;
The imaginary part of the number.

const string toString(scope void delegate(const(char)[]) sink = null, string formatSpec = "%s");
Converts the complex number to a string representation.

If a sink delegate is specified, the string is passed to it and this function returns null. Otherwise, this function returns the string representation directly.

The output format is controlled via formatSpec, which should consist of a single POSIX format specifier, including the percent (%) character. Note that complex numbers are floating point numbers, so the only valid format characters are 'e', 'f', 'g', 'a', and 's', where 's' gives the default behaviour. Positional parameters are not valid in this context.

See the std.format documentation for more information.

pure nothrow @safe T abs(T)(Complex!(T) z);
Calculates the absolute value (or modulus) of a complex number.

pure nothrow @safe T arg(T)(Complex!(T) z);
Calculates the argument (or phase) of a complex number.

pure nothrow @safe Complex!(T) conj(T)(Complex!(T) z);
Returns the complex conjugate of a complex number.

pure nothrow @safe Complex!(CommonType!(T, U)) fromPolar(T, U)(T modulus, U argument);
Constructs a complex number given its absolute value and argument.

pure nothrow @safe Complex!(T) sin(T)(Complex!(T) z);
pure nothrow @safe Complex!(T) cos(T)(Complex!(T) z);
Trigonometric functions.

pure nothrow @trusted Complex!(real) expi(real y);
Calculates cos(y) + i sin(y).

Note:
expi is included here for convenience and for easy migration of code that uses std.math.expi. Unlike std.math.expi, which uses the x87 fsincos instruction when possible, this function is no faster than calculating cos(y) and sin(y) separately.

pure nothrow @safe Complex!(T) sqrt(T)(Complex!(T) z);
Square root.

Copyright (c) 2010, Lars T. Kyllingstad. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.concurrency

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 Cid in this implementation), which allows messages to be sent to in-process threads, on-host processes, and foreign-host 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.

Right now, only in-process threads are supported and referenced by a more specialized handle called a Tid. It is effectively a subclass of Cid, with additional features specific to in-process messaging.

Synposis:
 import std.stdio;
 import std.concurrency;

 void spawnedFunc(Tid tid)
 {
     // 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(tid, true);
 }

 void main()
 {
     // Start spawnedFunc in a new thread.
     auto tid = spawn(&spawnedFunc, thisTid);

     // Send the number 42 to this new thread.
     send(tid, 42);

     // Receive the result code.
     auto wasSuccessful = receiveOnly!(bool);
     assert(wasSuccessful);
     writeln("Successfully printed number.");
 }
Standard input
Command line arguments
Application output

License:
Boost License 1.0.

Authors:
Sean Kelly, Alex Rønne Petersen

Source:
std/concurrency.d

class MessageMismatch: object.Exception;
Thrown on calls to receiveOnly if a message other than the type the receiving thread expected is sent.

class OwnerTerminated: object.Exception;
Thrown on calls to receive if the thread that spawned the receiving thread has terminated and no more messages exist.

class LinkTerminated: object.Exception;
Thrown if a linked thread has terminated.

class PriorityMessageException: object.Exception;
Thrown if a message was sent to a thread via std.concurrency.prioritySend and the receiver does not have a handler for a message of this type.

Variant message;
The message that was sent.

class MailboxFull: object.Exception;
Thrown on mailbox crowding if the mailbox is configured with OnCrowding.throwException.

struct Tid;
An opaque type used to represent a logical local process.

@property Tid thisTid();
Returns the caller's Tid.

template isSpawnable(F, T...)

Tid spawn(F, T...)(F fn, T args);
Executes the supplied function in a new context represented by Tid. The calling context is designated as the owner of the new context. When the owner context terminated an OwnerTerminated message will be sent to the new context, causing an OwnerTerminated exception to be thrown on receive().

Parameters:
fn | The function to execute.
args | Arguments to the function.

Returns:
A Tid representing the new context.

Notes:
args must not have unshared aliasing. In other words, all arguments to fn must either be shared or 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);
 }
Standard input
Command line arguments
Application output

Tid spawnLinked(F, T...)(F fn, T args);
Executes the supplied function in a new context represented by Tid. This new context is linked to the calling context so that if either it or the calling context 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().

Parameters:
fn | The function to execute.
args | Arguments to the function.

Returns:
A Tid representing the new context.

void send(T...)(Tid tid, T vals);
Sends the supplied value to the context represented by tid. As with std.concurrency.spawn, T must not have unshared aliasing.

void prioritySend(T...)(Tid tid, T vals);
Send a message to tid but place it at the front of 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 receive(T...)(T ops);
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 std.variant.Variant is included as the last argument to receive, it will match any message that was not matched by an earlier delegate. If more than one argument is sent, the Variant will contain a std.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);
 }
Standard input
Command line arguments
Application output

receiveOnlyRet!(T) receiveOnly(T...)();
Receives only messages with arguments of types T.

Throws:
MessageMismatch if a message of types other than T is received.

Returns:
The received message. If T.length is greater than one, the message will be packed into a std.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");
 }
Standard input
Command line arguments
Application output

bool receiveTimeout(T...)(Duration duration, T ops);
Same as receive except that rather than wait forever for a message, it waits until either it receives a message or the given core.time.Duration has passed. It returns true if it received a message and false if it timed out waiting for one.

enum OnCrowding;
These behaviors may be specified when a mailbox is full.

block
Wait until room is available.

throwException
Throw a MailboxFull exception.

ignore
Abort the send and return.

void setMaxMailboxSize(Tid tid, size_t messages, OnCrowding doThis);
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.

Parameters:
Tid tid | The Tid of the thread for which this limit should be set.
size_t messages | The maximum number of messages or zero if no limit.
OnCrowding doThis | The behavior executed when a message is sent to a full mailbox.

void setMaxMailboxSize(Tid tid, size_t messages, bool function(Tid) onCrowdingDoThis);
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.

Parameters:
Tid tid | The Tid of the thread for which this limit should be set.
size_t messages | The maximum number of messages or zero if no limit.
bool function(Tid) onCrowdingDoThis | The routine called when a message is sent to a full mailbox.

bool register(string name, Tid tid);
Associates name with tid in a process-local map. When the thread represented by tid termiantes, any names associated with it will be automatically unregistered.

Parameters:
string name | The name to associate with tid.
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 unregister(string name);
Removes the registered name associated with a tid.

Parameters:
string name The name to unregister.

Returns:
true if the name is registered, false if not.

Tid locate(string name);
Gets the Tid associated with name.

Parameters:
string name The name to locate within the registry.

Returns:
The associated Tid or Tid.init if name is not registered.

struct List(T);

Copyright Sean Kelly 2009 - 2010. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.container

Defines generic containers.

Source:
std/container.d

License:
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at boost.org/LICENSE_1_0.txt).

Authors:
Steven Schveighoffer, Andrei Alexandrescu

Container primitives. Below, C means a container type, c is a value of container type, nx represents the effective length of value x, which could be a single element (in which case nx is 1), a container, or a range.
Syntax | Ο(·) | Description
C(x) | nx | Creates a container of type C from either another container or a range.
c.dup | nc | Returns a duplicate of the container.
c ~ x | nc + nx | Returns the concatenation of c and r. x may be a single element or an input range.
x ~ c | nc + nx | Returns the concatenation of x and c. x may be a single element or an input range type.
Iteration
c.Range |  | The primary range type associated with the container.
c[] | log nc | Returns a range iterating over the entire container, in a container-defined order.
c[a .. b] | log nc | Fetches a portion of the container from key a to key b.
Capacity
c.empty | 1 | Returns true if the container has no elements, false otherwise.
c.length | log nc | Returns the number of elements in the container.
c.length = n | nc + n | Forces the number of elements in the container to n. If the container ends up growing, the added elements are initialized in a container-dependent manner (usually with T.init).
c.capacity | log nc | Returns the maximum number of elements that can be stored in the container without triggering a reallocation.
c.reserve(x) | nc | Forces capacity to at least x without reducing it.
Access
c.front | log nc | Returns the first element of the container, in a container-defined order.
c.moveFront | log nc | Destructively reads and returns the first element of the container. The slot is not removed from the container; it is left initalized with T.init. This routine need not be defined if front returns a ref.
c.front = v | log nc | Assigns v to the first element of the container.
c.back | log nc | Returns the last element of the container, in a container-defined order.
c.moveBack | log nc | Destructively reads and returns the last element of the container. The slot is not removed from the container; it is left initalized with T.init. This routine need not be defined if front returns a ref.
c.back = v | log nc | Assigns v to the last element of the container.
c[x] | log nc | Provides indexed access into the container. The index type is container-defined. A container may define several index types (and consequently overloaded indexing).
c.moveAt(x) | log nc | Destructively reads and returns the value at position x. The slot is not removed from the container; it is left initialized with T.init.
c[x] = v | log nc | Sets element at specified index into the container.
c[x] op= v | log nc | Performs read-modify-write operation at specified index into the container.
Operations
e in c | log nc | Returns nonzero if e is found in c.
c.lowerBound(v) | log nc | Returns a range of all elements strictly less than v.
c.upperBound(v) | log nc | Returns a range of all elements strictly greater than v.
c.equalRange(v) | log nc | Returns a range of all elements in c that are equal to v.
Modifiers
c ~= x | nc + nx | Appends x to c. x may be a single element or an input range type.
c.clear() | nc | Removes all elements in c.
c.insert(x) | nx * log nc | Inserts x in c at a position (or positions) chosen by c.
c.stableInsert(x) | nx * log nc | Same as c.insert(x), but is guaranteed to not invalidate any ranges.
c.linearInsert(v) | nc | Same as c.insert(v) but relaxes complexity to linear.
c.stableLinearInsert(v) | nc | Same as c.stableInsert(v) but relaxes complexity to linear.
c.removeAny() | log nc | Removes some element from c and returns it.
c.stableRemoveAny() | log nc | Same as c.removeAny(), but is guaranteed to not invalidate any iterators.
c.insertFront(v) | log nc | Inserts v at the front of c.
c.stableInsertFront(v) | log nc | Same as c.insertFront(v), but guarantees no ranges will be invalidated.
c.insertBack(v) | log nc | Inserts v at the back of c.
c.stableInsertBack(v) | log nc | Same as c.insertBack(v), but guarantees no ranges will be invalidated.
c.removeFront() | log nc | Removes the element at the front of c.
c.stableRemoveFront() | log nc | Same as c.removeFront(), but guarantees no ranges will be invalidated.
c.removeBack() | log nc | Removes the value at the back of c.
c.stableRemoveBack() | log nc | Same as c.removeBack(), but guarantees no ranges will be invalidated.
c.remove(r) | nr * log nc | Removes range r from c.
c.stableRemove(r) | nr * log nc | Same as c.remove(r), but guarantees iterators are not invalidated.
c.linearRemove(r) | nc | Removes range r from c.
c.stableLinearRemove(r) | nc | Same as c.linearRemove(r), but guarantees iterators are not invalidated.
c.removeKey(k) | log nc | Removes an element from c by using its key k. The key's type is defined by the container.

Container make(Container, T...)(T arguments);
Container make(Container, T...)(T arguments);
Returns an initialized container. This function is mainly for eliminating construction differences between class containers and struct containers.

struct SList(T);
Implements a simple and fast singly-linked list.

this(U)(U[] values...);
Constructor taking a number of nodes

this(Stuff)(Stuff stuff);
Constructor taking an input range

const bool opEquals(const SList rhs);
const bool opEquals(ref const SList rhs);
Comparison for equality.

Complexity:
Ο(min(n, n1)) where n1 is the number of elements in rhs.

struct Range;
Defines the container's primary range, which embodies a forward range.

const bool empty();
T front();
void front(T value);
void popFront();
Input range primitives.

Range save();
Forward range primitive.

const bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

SList dup();
Duplicates the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

Range opSlice();
Returns a range that iterates over all elements of the container, in forward order.

Complexity:
Ο(1)

T front();
Forward to opSlice().front.

Complexity:
Ο(1)

void front(T value);
Forward to opSlice().front(value).

Complexity:
Ο(1)

SList opBinary(string op, Stuff)(Stuff rhs);
Returns a new SList that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

void clear();
Removes all contents from the SList.

Postcondition:
empty

Complexity:
Ο(1)

size_t insertFront(Stuff)(Stuff stuff);
size_t insertFront(Stuff)(Stuff stuff);
alias insertFront insert;
alias insert stableInsert;
alias insertFront stableInsertFront;
Inserts stuff to the front of the container. stuff can be a value convertible to T or a range of objects convertible to 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:
Ο(m), where m is the length of stuff

T removeAny();
alias removeAny stableRemoveAny;
Picks one value from the front of the container, removes it from the container, and returns it.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(1).

void removeFront();
alias removeFront stableRemoveFront;
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:
!empty

Complexity:
Ο(1).

size_t removeFront(size_t howMany);
alias removeFront stableRemoveFront;
Removes 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 howMany elements. Instead, if 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:
Ο(howMany * log(n)).

size_t insertAfter(Stuff)(Range r, Stuff stuff);
Inserts stuff after range 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 r as a potentially fast way to reach the last node in the list. Ideally r is positioned near or at the last element of the list.

stuff can be a value convertible to T or a range of objects convertible to 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:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

Examples:
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)(Take!(Range) r, Stuff stuff);
alias insertAfter stableInsertAfter;
Similar to 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 r, use insertAfter(take(r, 1), stuff). The complexity of that operation only depends on the number of elements in stuff.

Precondition:
r.original.empty || r.maxLength > 0

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

Range linearRemove(Range r);
Removes a range from the list in linear time.

Returns:
An empty range.

Complexity:
Ο(n)

Range linearRemove(Take!(Range) r);
alias linearRemove stableLinearRemove;
Removes a Take!Range from the list in linear time.

Returns:
A range comprehending the elements after the removed range.

Complexity:
Ο(n)

struct DList(T);
Implements a doubly-linked list.

DList uses neither reference nor value semantics. They can be seen as several different handles into an external chain of nodes. Several different DLists can all reference different points in a same chain.

DList.Range is, for all intents and purposes, a DList with range semantics. The DList.Range has a view directly into the chain itself. It is not tied to its parent DList, and may be used to operate on other lists (that point to the same chain).

The ONLY operation that can invalidate a DList or DList.Range, but which will invalidate BOTH, is the remove operation, if the cut Range overlaps with the boundaries of another DList or DList.Range.

Example:
auto a = DList!int([3, 4]); //Create a new chain
auto b = a; //Point to the same chain
// (3 - 4)
assert(a[].equal([3, 4]));
assert(b[].equal([3, 4]));

b.stableInsertFront(1); //insert before of b
b.stableInsertBack(5); //insert after of b
// (2 - (3 - 4) - 5)
assert(a[].equal([3, 4])); //a is not changed
assert(b[].equal([1, 3, 4, 5])); // but b is changed

a.stableInsertFront(2); //insert in front of a, this will insert "inside" the chain
// (1 - (2 - 3 - 4) - 5)
assert(a[].equal([2, 3, 4])); //a is modified
assert(b[].equal([1, 2, 3, 4, 5])); //and so is b;

a.remove(a[]); //remove all the elements of a: This will cut them from the chain;
// (1 - 5)
assert(a[].empty); //a is empty
assert(b[].equal([1, 5])); //b has lost some of its elements;

a.insert(2); //insert in a. This will create a new chain
// (2)
// (1 - 5)
assert(a[].equal([2])); //a is a new chain
assert(b[].equal([1, 5])); //b is unchanged;

this(U)(U[] values...);
Constructor taking a number of nodes

this(Stuff)(Stuff stuff);
Constructor taking an input range

const bool opEquals(ref const DList rhs);
Comparison for equality.

Complexity:
Ο(min(n, n1)) where n1 is the number of elements in rhs.

struct Range;
Defines the container's primary range, which embodies a bidirectional range.

bool empty();
T front();
void front(T value);
void popFront();
Input range primitives.

Range save();
Forward range primitive.

T back();
void back(T value);
void popBack();
Bidirectional range primitives.

bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

DList dup();
Duplicates the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

Range opSlice();
Returns a range that iterates over all elements of the container, in forward order.

Complexity:
Ο(1)

T front();
Forward to opSlice().front.

Complexity:
Ο(1)

void front(T value);
Forward to opSlice().front(value).

Complexity:
Ο(1)

T back();
Forward to opSlice().back.

Complexity:
Ο(1)

void back(T value);
Forward to opSlice().back(value).

Complexity:
Ο(1)

DList opBinary(string op, Stuff)(Stuff rhs);
DList opBinary(string op, Stuff)(Stuff rhs);
Returns a new DList that's the concatenation of this and its argument.

DList opBinaryRight(string op, Stuff)(Stuff rhs);
DList opBinaryRight(string op, Stuff)(Stuff rhs);
Returns a new DList that's the concatenation of the argument and this

DList opOpAssign(string op, Stuff)(Stuff rhs);
DList opOpAssign(string op, Stuff)(Stuff rhs);
Appends the contents of stuff into this.

void clear();
Removes all contents from the DList.

Postcondition:
empty

Complexity:
Ο(1)

size_t insertFront(Stuff)(Stuff stuff);
size_t insertBack(Stuff)(Stuff stuff);
alias insertBack insert;
alias insert stableInsert;
alias insertFront stableInsertFront;
alias insertBack stableInsertBack;
Inserts stuff to the front/back of the container. stuff can be a value convertible to T or a range of objects convertible to 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:
Ο(log(n))

T removeAny();
alias removeAny stableRemoveAny;
Picks one value from the front of the container, removes it from the container, and returns it.

Elements are not actually removed from the chain, but the DList's, first/last pointer is advanced.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(1).

void removeFront();
alias removeFront stableRemoveFront;
void removeBack();
alias removeBack stableRemoveBack;
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.

Elements are not actually removed from the chain, but the DList's, first/last pointer is advanced.

Precondition:
!empty

Complexity:
Ο(1).

size_t removeFront(size_t howMany);
alias removeFront stableRemoveFront;
size_t removeBack(size_t howMany);
alias removeBack stableRemoveBack;
Removes 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 howMany elements. Instead, if 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.

Elements are not actually removed from the chain, but the DList's, first/last pointer is advanced.

Returns:
The number of elements removed

Complexity:
Ο(howMany * log(n)).

size_t insertBefore(Stuff)(Range r, Stuff stuff);
alias insertBefore stableInsertBefore;
size_t insertAfter(Stuff)(Range r, Stuff stuff);
alias insertAfter stableInsertAfter;
Inserts stuff after range r, which must be a non-empty range previously extracted from this container.

stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Elements are not actually removed from the chain, but the DList's, first/last pointer is advanced.

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

Range remove(Range r);
Range linearRemove(R)(R r);
Range linearRemove(R)(R r);
Removes all elements belonging to r, which must be a range obtained originally from this container.

This function actually removes the elements from the chain. This is the only function that may invalidate a range, as it cuts the chain of elements: Ranges (and other DList) that contain r or that are inside r, as well a r itself, are never invalidated. Ranges (and other DList) which partially overlap with r will be cut, and invalidated.

Returns:
A range spanning the remaining elements in the container that initially were right after r.

Complexity:
Ο(1)

Range linearRemove(R)(R r);
linearRemove functions as remove, but also accepts ranges that are result the of a take operation. This is a convenient way to remove a fixed amount of elements from the range.

Complexity:
Ο(r.walkLength)

alias remove stableRemove;
alias linearRemove stableLinearRemove;
(RED Scheduled for deprecation. These methods are not actually stable. Use the standard remove or linearRemove instead.

struct Array(T) if (!is(T : const(bool)));
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. Array uses malloc and free for managing its own memory.

const bool opEquals(const Array rhs);
const bool opEquals(ref const Array rhs);
Comparison for equality.

struct Range;
Defines the container's primary range, which is a random-access range.

Array dup();
Duplicates the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

const bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

const size_t length();
const size_t opDollar();
Returns the number of elements in the container.

Complexity:
Ο(1).

size_t capacity();
Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion.

Complexity:
Ο(1)

void reserve(size_t elements);
Ensures sufficient capacity to accommodate e elements.

Postcondition:
capacity >= e

Complexity:
Ο(1)

Range opSlice();
Returns a range that iterates over elements of the container, in forward order.

Complexity:
Ο(1)

Range opSlice(size_t a, size_t b);
Returns a range that iterates over elements of the container from index a up to (excluding) index b.

Precondition:
a <= b && b <= length

Complexity:
Ο(1)

T front();
void front(T value);
T back();
void back(T value);
Forward to opSlice().front and opSlice().back, respectively.

Precondition:
!empty

Complexity:
Ο(1)

T opIndex(size_t i);
void opIndexUnary(string op)(size_t i);
T opIndexUnary(string op)(size_t i);
void opIndexAssign(T value, size_t i);
void opIndexOpAssign(string op)(T value, size_t i);
Indexing operators yield or modify the value at a specified index.

Precondition:
i < length

Complexity:
Ο(1)

void opSliceAssign(T value);
void opSliceUnary(string op)(size_t i, size_t j);
void opSliceOpAssign(string op)(T value);
void opSliceOpAssign(string op)(T value, size_t i, size_t j);
Slicing operations execute an operation on an entire slice.

Precondition:
i < j && j < length

Complexity:
Ο(slice.length)

Array opBinary(string op, Stuff)(Stuff stuff);
Returns a new container that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

Complexity:
Ο(n + m), where m is the number of elements in stuff

void opOpAssign(string op, Stuff)(Stuff stuff);
Forwards to insertBack(stuff).

void clear();
Removes all contents from the container. The container decides how capacity is affected.

Postcondition:
empty

Complexity:
Ο(n)

void length(size_t newLength);
Sets the number of elements in the container to newSize. If newSize is greater than length, the added elements are added to unspecified positions in the container and initialized with T.init.

Complexity:
Ο(abs(n - newLength))

Postcondition:
length == newLength

T removeAny();
alias removeAny stableRemoveAny;
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, but document the exact behavior. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(log(n)).

size_t insertBack(Stuff)(Stuff stuff);
alias insertBack insert;
Inserts value to the front or back of the container. stuff can be a value convertible to T or a range of objects convertible to 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:
Ο(m * log(n)), where m is the number of elements in stuff

void removeBack();
alias removeBack stableRemoveBack;
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:
!empty

Complexity:
Ο(log(n)).

size_t removeBack(size_t howMany);
alias removeBack stableRemoveBack;
Removes 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 howMany elements. Instead, if 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:
Ο(howMany).

size_t insertBefore(Stuff)(Range r, Stuff stuff);
size_t insertBefore(Stuff)(Range r, Stuff stuff);
size_t insertAfter(Stuff)(Range r, Stuff stuff);
size_t replace(Stuff)(Range r, Stuff stuff);
size_t replace(Stuff)(Range r, Stuff stuff);
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to T or a range of objects convertible to 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:
Ο(n + m), where m is the length of stuff

Range linearRemove(Range r);
alias remove stableLinearRemove;
Removes all elements belonging to 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 r.

Complexity:
Ο(n - m), where m is the number of elements in r

struct BinaryHeap(Store, alias less = "a < b") if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[])));
Implements a binary heap container on top of a given random-access range type (usually T[]) or a random-access container type (usually Array!T). The documentation of BinaryHeap will refer to the underlying range or container as the store of the heap.

The binary heap induces structure over the underlying store such that accessing the largest element (by using the front property) is a Ο(1) operation and extracting it (by using the removeFront() method) is done fast in Ο(log n) time.

If less is the less-than operator, which is the default option, then BinaryHeap defines a so-called max-heap that optimizes extraction of the largest elements. To define a min-heap, instantiate BinaryHeap with "a > b" as its predicate.

Simply extracting elements from a BinaryHeap container is tantamount to lazily fetching elements of Store in descending order. Extracting elements from the BinaryHeap to completion leaves the underlying store sorted in ascending order but, again, yields elements in descending order.

If Store is a range, the BinaryHeap cannot grow beyond the size of that range. If Store is a container that supports insertBack, the BinaryHeap may grow by adding elements to the container.

Example:
// 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);
// largest element
assert(h.front == 16);
// a has the heap property
assert(equal(a, [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ]));

this(Store s, size_t initialSize = size_t.max);
Converts the store s into a heap. If initialSize is specified, only the first initialSize elements in s are transformed into a heap, after which the heap can grow up to r.length (if Store is a range) or indefinitely (if Store is a container with insertBack). Performs Ο(min(r.length, initialSize)) evaluations of less.

void acquire(Store s, size_t initialSize = size_t.max);
Takes ownership of a store. After this, manipulating s may make the heap work incorrectly.

void assume(Store s, size_t initialSize = size_t.max);
Takes ownership of a store assuming it already was organized as a heap.

auto release();
Clears the heap. Returns the portion of the store from 0 up to length, which satisfies the heap property.

bool empty();
Returns true if the heap is empty, false otherwise.

BinaryHeap dup();
Returns a duplicate of the heap. The underlying store must also support a dup method.

size_t length();
Returns the length of the heap.

size_t capacity();
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).

ElementType!(Store) front();
Returns a copy of the front of the heap, which is the largest element according to less.

void clear();
Clears the heap by detaching it from the underlying store.

size_t insert(ElementType!(Store) value);
Inserts value into the store. If the underlying store is a range and length == capacity, throws an exception.

void removeFront();
Removes the largest element from the heap.

ElementType!(Store) removeAny();
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 removeFront with heaps of objects that are expensive to copy.

void replaceFront(ElementType!(Store) value);
Replaces the largest element in the store with value.

bool conditionalInsert(ElementType!(Store) value);
If the heap has room to grow, inserts value into the store and returns true. Otherwise, if less(value, front), calls replaceFront(value) and returns again true. Otherwise, leaves the heap unaffected and returns false. This method is useful in scenarios where the smallest k elements of a set of candidates must be collected.

BinaryHeap!(Store) heapify(Store)(Store s, size_t initialSize = size_t.max);
Convenience function that returns a BinaryHeap!Store object initialized with s and initialSize.

struct Array(T) if (is(T == bool));
Array specialized for bool. Packs together values efficiently by allocating one bit per element.

struct Range;
Defines the container's primary range.

Range save();
bool empty();
T front();
void front(bool value);
T moveFront();
void popFront();
T back();
T moveBack();
void popBack();
T opIndex(size_t i);
void opIndexAssign(T value, size_t i);
T moveAt(size_t i);
const ulong length();
Range primitives

bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

Array!(bool) dup();
Returns a duplicate of the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

ulong length();
Returns the number of elements in the container.

Complexity:
Ο(log(n)).

ulong capacity();
Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion.

Complexity:
Ο(log(n)).

void reserve(ulong e);
Ensures sufficient capacity to accommodate n elements.

Postcondition:
capacity >= n

Complexity:
Ο(log(e - capacity)) if e > capacity, otherwise Ο(1).

Range opSlice();
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 opSlice().

Complexity:
Ο(log(n))

Range opSlice(ulong a, ulong b);
Returns a range that iterates the container between two specified positions.

Complexity:
Ο(log(n))

bool front();
void front(bool value);
bool back();
void back(bool value);
Equivalent to opSlice().front and opSlice().back, respectively.

Complexity:
Ο(log(n))

bool opIndex(ulong i);
void opIndexAssign(bool value, ulong i);
void opIndexOpAssign(string op)(bool value, ulong i);
T moveAt(ulong i);
Indexing operators yield or modify the value at a specified index.

Array!(bool) opBinary(string op, Stuff)(Stuff rhs);
Returns a new container that's the concatenation of this and its argument.

Complexity:
Ο(n + m), where m is the number of elements in stuff

Array!(bool) opOpAssign(string op, Stuff)(Stuff stuff);
Forwards to insertAfter(this[], stuff).

void clear();
Removes all contents from the container. The container decides how capacity is affected.

Postcondition:
empty

Complexity:
Ο(n)

void length(ulong newLength);
Sets the number of elements in the container to newSize. If newSize is greater than length, the added elements are added to the container and initialized with ElementType.init.

Complexity:
Ο(abs(n - newLength))

Postcondition:
length == newLength

alias insertBack insert;
alias insertBack stableInsert;
Inserts stuff in the container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType.

The stable version guarantees that ranges iterating over the container are never invalidated. Client code that counts on non-invalidating insertion should use stableInsert.

Returns:
The number of elements added.

Complexity:
Ο(m * log(n)), where m is the number of elements in stuff

alias insertBack linearInsert;
alias insertBack stableLinearInsert;
Same as insert(stuff) and stableInsert(stuff) respectively, but relax the complexity constraint to linear.

T removeAny();
alias removeAny stableRemoveAny;
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:
!empty

Returns:
The element removed.

Complexity:
Ο(log(n))

ulong insertBack(Stuff)(Stuff stuff);
ulong insertBack(Stuff)(Stuff stuff);
alias insertBack stableInsertBack;
Inserts value to the back of the container. stuff can be a value convertible to ElementType or a range of objects convertible to 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:
Ο(log(n))

void removeBack();
alias removeBack stableRemoveBack;
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 howMany instructs removal of that many elements. If howMany > n, all elements are removed and no exception is thrown.

Precondition:
!empty

Complexity:
Ο(log(n)).

ulong removeBack(ulong howMany);
Removes 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 howMany elements. Instead, if 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:
Ο(howMany * log(n)). ditto

ulong insertBefore(Stuff)(Range r, Stuff stuff);
alias insertBefore stableInsertBefore;
ulong insertAfter(Stuff)(Range r, Stuff stuff);
alias insertAfter stableInsertAfter;
size_t replace(Stuff)(Range r, Stuff stuff);
alias replace stableReplace;
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to ElementType or a range of objects convertible to 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:
Ο(n + m), where m is the length of stuff

Range linearRemove(Range r);
alias linearRemove stableLinearRemove;
Removes all elements belonging to 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 r.

Complexity:
Ο(n)

class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) if (is(typeof(binaryFun!(less)(T.init, T.init))));
Implementation of a red-black tree container.

All inserts, removes, searches, and any function in general has complexity of Ο(lg(n)).

To use a different comparison than "a < b", pass a different operator string that can be used by std.functional.binaryFun, or pass in a function, delegate, functor, or any type where less(a, b) results in a bool value.

Note that less should produce a strict ordering. That is, for two unequal elements a and b, less(a, b) == !less(b, a). less(a, a) should always equal false.

If allowDuplicates is set to true, then inserting the same element more than once continues to add more elements. If it is false, duplicate elements are ignored on insertion. If duplicates are allowed, then new elements are inserted after all existing duplicate elements.

alias T Elem;
Element type for the tree

struct Range;
The range type for RedBlackTree

const bool empty();
Returns true if the range is empty

Elem front();
Returns the first element in the range

Elem back();
Returns the last element in the range

void popFront();
pop the front element from the range

complexity:
amortized Ο(1)

void popBack();
pop the back element from the range

complexity:
amortized Ο(1)

Range save();
Trivial save implementation, needed for isForwardRange.

bool empty();
Check if any elements exist in the container. Returns false if at least one element exists.

size_t length();
Returns the number of elements in the container.

Complexity:
Ο(1).

RedBlackTree dup();
Duplicate this container. The resulting container contains a shallow copy of the elements.

Complexity:
Ο(n)

Range opSlice();
Fetch a range that spans all the elements in the container.

Complexity:
Ο(log(n))

Elem front();
The front element in the container

Complexity:
Ο(log(n))

Elem back();
The last element in the container

Complexity:
Ο(log(n))

bool opBinaryRight(string op)(Elem e);
in operator. Check to see if the given element exists in the container.

Complexity:
Ο(log(n))

bool opEquals(Object rhs);
Compares two trees for equality.

Complexity:
Ο(n*log(n))

void clear();
Removes all elements from the container.

Complexity:
Ο(1)

size_t stableInsert(Stuff)(Stuff stuff);
Insert a single element in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(log(n))

size_t stableInsert(Stuff)(Stuff stuff);
alias stableInsert insert;
Insert a range of elements in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(m * log(n))

Elem removeAny();
Remove an element from the container and return its value.

Complexity:
Ο(log(n))

void removeFront();
Remove the front element from the container.

Complexity:
Ο(log(n))

void removeBack();
Remove the back element from the container.

Complexity:
Ο(log(n))

Range remove(Range r);
Removes the given range from the container.

Returns:
A range containing all of the elements that were after the given range.

Complexity:
Ο(m * log(n)) (where m is the number of elements in the range)

Range remove(Take!(Range) r);
Removes the given Take!Range from the container

Returns:
A range containing all of the elements that were after the given range.

Complexity:
Ο(m * log(n)) (where m is the number of elements in the range)

size_t removeKey(U...)(U elems);
size_t removeKey(U)(U[] elems);
size_t removeKey(Stuff)(Stuff stuff);
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 allowDuplicates is true, duplicates are removed only if duplicate values are given.

Returns:
The number of elements removed.

Complexity:
Ο(m log(n)) (where m is the number of elements to remove)

Examples:
auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7);
rbt.removeKey(1, 4, 7);
assert(std.algorithm.equal(rbt[], [0, 1, 1, 5]));
rbt.removeKey(1, 1, 0);
assert(std.algorithm.equal(rbt[], [5]));

Range upperBound(Elem e);
Get a range from the container with all elements that are > e according to the less comparator

Complexity:
Ο(log(n))

Range lowerBound(Elem e);
Get a range from the container with all elements that are < e according to the less comparator

Complexity:
Ο(log(n))

Range equalRange(Elem e);
Get a range from the container with all elements that are == e according to the less comparator

Complexity:
Ο(log(n))

this();

this(Elem[] elems...);
Constructor. Pass in an array of elements, or individual elements to initialize the tree with.

auto redBlackTree(E)(E[] elems...);
auto redBlackTree(bool allowDuplicates, E)(E[] elems...);
auto redBlackTree(alias less, E)(E[] elems...);
auto redBlackTree(alias less, bool allowDuplicates, E)(E[] elems...);
Convenience function for creating a RedBlackTree!E from a list of values.

Examples:
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);

Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. _to!TargetType(value) (and not some variant of toImpl)." class="tip button"> Page wiki View or edit the community-maintained wiki page associated with this page.

std.conv

A one-stop shop for converting values from one type to another.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara

Source:
std/conv.d

class ConvException: object.Exception;
Thrown on conversion errors.

class ConvOverflowException: std.conv.ConvException;
Thrown on conversion overflow errors.

template to(T)
The to family of functions converts a value from type Source to type Target. The source type is deduced and the target type must be specified, for example the expression to!int(42.0) converts the number 42 from double to int. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., 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 roundTo.)

Examples:
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 real (when 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 atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is:
Integer: Sign UnsignedInteger
UnsignedInteger
Sign:
    +
    -

For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
    DecimalDigit
    DecimalDigit 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]).dup;
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 to!short applies to an int, to!wstring applies to a string, to!string applies to a double, and to!(double[]) applies to an int[]. The conversion might throw an exception because to!short might fail the range check.

T toImpl(T, S)(S value);
If the source type is implicitly convertible to the target type, to simply performs the implicit conversion.

T toImpl(T, S)(S value);
When source type supports member template function opCast, is is used.

T toImpl(T, S)(S value);
T toImpl(T, S)(S value);
When target type supports 'converting construction', it is used.
  • If target type is struct, T(value) is used.
  • If target type is class, new T(value) is used.

T toImpl(T, S)(S value);
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);
T toImpl(T, S)(S value, uint radix);
Stringnize conversion from all types is supported.
  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).
  • Converts array (other than strings) to string. Each element is converted by calling to!T.
  • Associative array to string conversion. Each element is printed by calling to!T.
  • Object to string conversion calls toString against the object or returns "null" if the object is null.
  • Struct to string conversion calls toString against the struct if it is defined.
  • For structs that do not define toString, the conversion to string produces the list of fields.
  • Enumerated types are converted to strings as their symbolic names.
  • Boolean values are printed as "true" or "false".
  • char, wchar, dchar to a string type.
  • Unsigned or signed integers to strings.
    [special case]
    Convert integral value to string in 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.
  • All floating point types to all string types.
  • Pointer to string conversions prints the pointer as a size_t value. If pointer is char*, treat it as C-style strings.

T toImpl(T, S)(S s, in T leftBracket, in T separator = ", ", in T rightBracket = "]");
T toImpl(T, S)(ref S s, in T leftBracket, in T separator = " ", in T rightBracket = "]");
T toImpl(T, S)(S s, in T leftBracket, in T keyval = ":", in T separator = ", ", in T rightBracket = "]");
T toImpl(T, S)(S s, in T nullstr);
T toImpl(T, S)(S s, in T left, in T separator = ", ", in T right = ")");
Deprecated. It will be removed in January 2013. Please use std.format.formattedWrite instead.

Conversions to string with optional configures.

T toImpl(T, S)(S value);
Narrowing numeric-numeric conversions throw when the value does not fit in the narrower type.

T toImpl(T, S)(S value);
Array-to-array conversion (except when target is a string type) converts each element in turn by using to.

T toImpl(T, S)(S value);
Associative array to associative array conversion converts each key and each value in turn.

T toImpl(T, S)(S value);
T toImpl(T, S)(S value, uint radix);
String to non-string conversion runs parsing.
  • When the source is a wide string, it is first converted to a narrow string and then parsed.
  • When the source is a narrow string, normal text parsing occurs.

template roundTo(Target)
Rounded conversion from floating point to integral.

Example:
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);
Rounded conversions do not work with non-integral target types.

Target parse(Target, Source)(ref Source s);
Target parse(Target, Source)(ref Source s, uint radix);
The parse family of functions works quite like the to family, except that (1) it only works with character ranges as input, (2) takes the input by reference and advances it to the position following the conversion, and (3) 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.

Example:
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 == "");

Target parse(Target, Source)(ref Source s);
Parsing one character off a string returns the character and bumps the string up one position.

Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',');
Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',');
Parses an array from a string given the left bracket (default '['), right bracket (default ']'), and element separator (by default ',').

Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar keyval = ':', dchar comma = ',');
Parses an associative array from a string given the left bracket (default '['), right bracket (default ']'), key-value separator (default ':'), and element seprator (by default ',').

string text(T...)(T args);
wstring wtext(T...)(T args);
dstring dtext(T...)(T args);
Convenience functions for converting any number and types of arguments into text (the three character widths).

Example:
assert(text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz");
assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);

int octal(string num)();
long octal(string num)();
uint octal(string num)();
ulong octal(string num)();
template octal(alias s) if (isIntegral!(typeof(s)))
The octal facility is intended as an experimental facility to replace octal literals starting with '0', which many find confusing. Using octal!177 or octal!"177" instead of 0177 as an octal literal makes code clearer and the intent more visible. If use of this facility becomes preponderent, a future version of the language may deem old-style octal literals deprecated.

The rules for strings are the usual for literals: If it can fit in an int, it is an int. Otherwise, it is a long. But, if the user specifically asks for a long with the L suffix, always give the long. Give an unsigned iff it is asked for with the U or u suffix. Octals created from integers preserve the type of the passed-in integral.

Example:
// 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";

T* emplace(T)(T* chunk);
T* emplace(T)(T* chunk);
Given a pointer chunk to uninitialized memory (but already typed as T), constructs an object of non-class type T at that address.

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object (which is the same as chunk).

T* emplace(T, Args...)(T* chunk, Args args);
Given a pointer chunk to uninitialized memory (but already typed as a non-class type T), constructs an object of type T at that address from arguments args.

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object (which is the same as chunk).

T emplace(T, Args...)(void[] chunk, auto ref Args args);
Given a raw memory area chunk, constructs an object of class type T at that address. The constructor is passed the arguments Args. The chunk must be as least as large as T needs and should have an alignment multiple of T's alignment. (The size of a class instance is obtained by using _traits(classInstanceSize, T)).

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object.

T* emplace(T, Args...)(void[] chunk, auto ref Args args);
Given a raw memory area chunk, constructs an object of non-class type T at that address. The constructor is passed the arguments args, if any. The chunk must be as least as large as T needs and should have an alignment multiple of T's alignment.

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object.

Copyright Digital Mars 2007-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.csv

Implements functionality to read Comma Separated Values and its variants from a input range of 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 RFC-4180. CSV input should adhered to the following criteria, differences from RFC-4180 in parentheses.

  • A record is separated by a new line (CRLF,LF,CR)
  • A final record may end with a new line
  • A header may be provided as the first record in input
  • A record has fields separated by a comma (customizable)
  • A field containing new lines, commas, or double quotes should be enclosed in double quotes (customizable)
  • Double quotes in a field are escaped with a double quote
  • 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]);
     }
 }

When an input contains a header the 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:
Wikipedia Comma-separated values

License:
Boost License 1.0.

Authors:
Jesse Phillips

Source:
std/csv.d

class CSVException: object.Exception;
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 HeaderMismatchException for details.

When performing type conversions, std.ConvException.ConvException is stored in the next field.

size_t row;

size_t col;

class IncompleteCellException: std.csv.CSVException;
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.

dstring partialData;
Data pulled from input before finding a problem

This field is populated when using csvReader but not by csvNextToken as this data will have already been fed to the output range.

class HeaderMismatchException: std.csv.CSVException;
Exception thrown under different conditions based on the type of Contents.

Structure, Class, and Associative Array
  • When a header is provided but a matching column is not found

Other
  • When a header is provided but a matching column is not found
  • 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.

enum Malformed;
Determines the behavior for when an error is detected.

Disabling exception will follow these rules:
  • 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.
  • If the given header does not match the order in the input, the content will return as it is found in the input.
  • If the given header contains columns not found in the input they will be ignored.

ignore
No exceptions are thrown due to incorrect CSV.

throwException
Use exceptions when input has incorrect CSV.

auto csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Separator = char)(Range input, Separator delimiter = ',', Separator quote = '"');
Returns an input range for iterating over records found in input.

The 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 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 std.range.isInputRange. When Contents is a struct, class, or an associative array, the element type of R is Contents, otherwise the element type of R is itself a range with element type Contents.

Throws:
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.

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 Contents.

auto csvReader(Contents = string, Malformed ErrorLevel = Malformed.throwException, Range, Header, Separator = char)(Range input, Header header, Separator delimiter = ',', Separator quote = '"');
An optional header can be provided. The first record will be read in as the header. If Contents is a struct then the header provided is expected to correspond to the fields in the struct. When Contents is not a type which can contain the entire record, the 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 std.range.isInputRange. When Contents is a struct, class, or an associative array, the element type of R is Contents, otherwise the element type of R is itself a range with element type 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:
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.

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 Contents.

void csvNextToken(Range, Malformed ErrorLevel = Malformed.throwException, Separator, Output)(ref Range input, ref Output ans, Separator sep, Separator quote, bool startQuoted = false);
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.

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

Parameters:
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:
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.

Copyright 2011 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.datetime

Module containing Date/Time functionality.

This module provides:
  • Types to represent points in time: SysTime, Date, TimeOfDay, and DateTime.
  • Types to represent intervals of time.
  • Types to represent ranges over intervals of time.
  • Types to represent time zones (used by SysTime).
  • A platform-independent, high precision stopwatch type: StopWatch
  • Benchmarking functions.
  • Various helper functions.

Closely related to std.datetime is core.time, and some of the time types used in std.datetime come from there - such as core.time.Duration, core.time.TickDuration, and core.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) - 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).

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 Date (if they want dates but don't care about time), DateTime (if they want dates and times but don't care about time zones), 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). Date and DateTime are optimized for calendar-based operations, while SysTime is designed for dealing with time from the OS. Check out their specific documentation for more details.

To get the current time, use Clock.currTime. It will return the current time as a SysTime. To print it, toString is sufficient, but if using toISOString, toISOExtString, or toSimpleString, use the corresponding fromISOString, fromISOExtString, or fromISOExtString to create a 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. 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 in core.time which take "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 "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:
DateTimeException is an alias for core.time's 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 TimeException or DateTimeException).

See Also:
Introduction to std.datetime
ISO 8601
Wikipedia entry on TZ Database
List of Time Zones

License:
Boost License 1.0.

Authors:
Jonathan M Davis and Kato Shoichi

Source:
std/datetime.d

enum Month;
Represents the 12 months of the Gregorian year (January is 1).

jan

feb

mar

apr

may

jun

jul

aug

sep

oct

nov

dec

enum DayOfWeek;
Represents the 7 days of the Gregorian week (Sunday is 0).

sun

mon

tue

wed

thu

fri

sat

enum AllowDayOverflow;
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.

no
No, don't allow day overflow.

yes
Yes, allow day overflow.

enum Direction;
Indicates a direction in time. One example of its use is Interval's expand function which uses it to indicate whether the interval should be expanded backwards (into the past), forwards (into the future), or both.

bwd
Backward.

fwd
Forward.

both
Both backward and forward.

enum PopFirst;
Used to indicate whether popFront should be called immediately upon creating a range. The idea is that for some functions used to generate a range for an interval, 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 PopFirst.yes to indicate that the range should have popFront called on it before the range is returned so that 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 PopFirst.yes would tell the function which returned the range that 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 front, while when iterating backward, it would be the Easter prior to the original front). If PopFirst.no were used, then 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).

no
No, don't call popFront() before returning the range.

yes
Yes, call popFront() before returning the range.

enum AutoStart;
Used by StopWatch to indicate whether it should start immediately upon construction.

no
No, don't start the StopWatch when it is constructed.

yes
Yes, do start the StopWatch when it is constructed.

immutable string[] timeStrings;
Array of the strings representing time units, starting with the smallest unit and going to the largest. It does not include "nsecs".

Includes "hnsecs" (hecto-nanoseconds (100 ns)), "usecs" (microseconds), "msecs" (milliseconds), "seconds", "minutes", "hours", "days", "weeks", "months", and "years"

alias core.time.TimeException DateTimeException;
Exception type used by std.datetime. It's an alias to TimeException, which is what core.time uses. Either can be caught without concern about which module it came from.

class Clock;
Effectively a namespace to make it clear that the methods it contains are getting the time from the system clock. It cannot be instantiated.

static SysTime currTime(immutable TimeZone tz = LocalTime());
Returns the current time in the given time zone.

Throws:
ErrnoException (on Posix) or Exception (on Windows) if it fails to get the time of day.

static @property @trusted long currStdTime();
Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the current time.

Throws:
DateTimeException if it fails to get the time.

static @property @safe TickDuration currSystemTick();
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:
DateTimeException if it fails to get the time.

static @property @safe TickDuration currAppTick();
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:
DateTimeException if it fails to get the time.

struct SysTime;
SysTime is the type used to get the current time from the system or doing anything that involves time zones. Unlike DateTime, the time zone is an integral part of 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 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 DateTime would be the type to use. For system time, use SysTime.

Clock.currTime will return the current time as a SysTime. To convert a SysTime to a Date or DateTime, simply cast it. To convert a Date or DateTime to a SysTime, use SysTime's constructor, and pass in the intended time zone with it (or don't pass in a TimeZone, and the local time zone will be used). Be aware, however, that converting from a DateTime to a 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 SysTimes. Aside from DST though, there shouldn't be any conversion problems.

For using time zones other than local time or UTC, use PosixTimeZone on Posix systems (or on Windows, if providing the TZ Database files), and use WindowsTimeZone on Windows systems. The time in 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 SysTime. LocalTime is the TimeZone class which represents the local time, and UTC is the TimeZone class which represents UTC. SysTime uses LocalTime if no TimeZone is provided. For more details on time zones, see the documentation for TimeZone, PosixTimeZone, and WindowsTimeZone.

SysTime's range is from approximately 29,000 B.C. to approximately 29,000 A.D.

nothrow this(in DateTime dateTime, immutable TimeZone tz = null);
Parameters:
DateTime dateTime | The DateTime to use to set this SysTime's internal std time. As DateTime has no concept of time zone, tz is used as its time zone.
TimeZone tz | The TimeZone to use for this SysTime. If null, LocalTime will be used. The given DateTime is assumed to be in the given time zone.

this(in DateTime dateTime, in FracSec fracSec, immutable TimeZone tz = null);
Parameters:
DateTime dateTime | The DateTime to use to set this SysTime's internal std time. As DateTime has no concept of time zone, tz is used as its time zone.
FracSec fracSec | The fractional seconds portion of the time.
TimeZone tz | The TimeZone to use for this SysTime. If null, LocalTime will be used. The given DateTime is assumed to be in the given time zone.

Throws:
DateTimeException if fracSec is negative.

nothrow this(in Date date, immutable TimeZone tz = null);
Parameters:
Date date | The Date to use to set this SysTime's internal std time. As Date has no concept of time zone, tz is used as its time zone.
TimeZone tz | The TimeZone to use for this SysTime. If null, LocalTime will be used. The given Date is assumed to be in the given time zone.

pure nothrow this(long stdTime, immutable TimeZone tz = null);
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.

Parameters:
long stdTime | The number of hnsecs since midnight, January 1st, 1 A.D. UTC.
TimeZone tz | The TimeZone to use for this SysTime. If null, LocalTime will be used.

pure nothrow ref SysTime opAssign(ref const SysTime rhs);
Parameters:
SysTime rhs The SysTime to assign to this one.

pure nothrow ref SysTime opAssign(SysTime rhs);
Parameters:
SysTime rhs The SysTime to assign to this one.

const pure nothrow bool opEquals(const SysTime rhs);
const pure nothrow bool opEquals(ref const SysTime rhs);
Checks for equality between this SysTime and the given SysTime.

Note that the time zone is ignored. Only the internal std times (which are in UTC) are compared.

const pure nothrow int opCmp(in SysTime rhs);
Compares this SysTime with the given SysTime.

Time zone is irrelevant when comparing SysTimes.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

const nothrow @property short year();
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

@property void year(int year);
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

Parameters:
int year The year to set this SysTime's year to.

Throws:
DateTimeException if the new year is not a leap year and the resulting date would be on February 29th.

Examples:
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);

const @property ushort yearBC();
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Throws:
DateTimeException if isAD is true.

Examples:
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);

@property void yearBC(int year);
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Parameters:
int year The year B.C. to set this SysTime's year to.

Throws:
DateTimeException if a non-positive value is given.

Examples:
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)));

const nothrow @property Month month();
Month of a Gregorian Year.

Examples:
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);

@property void month(Month month);
Month of a Gregorian Year.

Parameters:
Month month The month to set this SysTime's month to.

Throws:
DateTimeException if the given month is not a valid month.

const nothrow @property ubyte day();
Day of a Gregorian Month.

Examples:
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);

@property void day(int day);
Day of a Gregorian Month.

Parameters:
int day The day of the month to set this SysTime's day to.

Throws:
DateTimeException if the given day is not a valid day of the current month.

const nothrow @property ubyte hour();
Hours past midnight.

@property void hour(int hour);
Hours past midnight.

Parameters:
int hour The hours to set this SysTime's hour to.

Throws:
DateTimeException if the given hour are not a valid hour of the day.

const nothrow @property ubyte minute();
Minutes past the current hour.

@property void minute(int minute);
Minutes past the current hour.

Parameters:
minutes The minute to set this SysTime's minute to.

Throws:
DateTimeException if the given minute are not a valid minute of an hour.

const nothrow @property ubyte second();
Seconds past the current minute.

@property void second(int second);
Seconds past the current minute.

Parameters:
int second The second to set this SysTime's second to.

Throws:
DateTimeException if the given second are not a valid second of a minute.

const nothrow @property FracSec fracSec();
Fractional seconds passed the second.

@property void fracSec(FracSec fracSec);
Fractional seconds passed the second.

Parameters:
FracSec fracSec The fractional seconds to set this SysTimes's fractional seconds to.

Throws:
DateTimeException if fracSec is negative.

const pure nothrow @property long stdTime();
The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal representation of SysTime.

pure nothrow @property void stdTime(long stdTime);
The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal representation of SysTime.

Parameters:
long stdTime The number of hnsecs since January 1st, 1 A.D. UTC.

const pure nothrow @property immutable(TimeZone) timezone();
The current time zone of this 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 SysTime's time zone before returning.

pure nothrow @property void timezone(immutable TimeZone timezone);
The current time zone of this 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 SysTime's time zone before returning.

Parameters:
tz The TimeZone to set this SysTime's time zone to.

const nothrow @property bool dstInEffect();
Returns whether DST is in effect for this SysTime.

const nothrow @property Duration utcOffset();
Returns what the offset from UTC is for this SysTime. It includes the DST offset in effect at that time (if any).

const nothrow SysTime toLocalTime();
Returns a SysTime with the same std time as this one, but with LocalTime as its time zone.

const pure nothrow SysTime toUTC();
Returns a SysTime with the same std time as this one, but with UTC as its time zone.

const pure nothrow SysTime toOtherTZ(immutable TimeZone tz);
Returns a SysTime with the same std time as this one, but with given time zone as its time zone.

const pure nothrow time_t toUnixTime();
Returns a time_t which represents the same time as this SysTime.

Note that like all conversions in std.datetime, this is a truncating conversion.

If time_t is 32 bits, rather than 64, and the result can't fit in a 32-bit value, then the closest value that can be held in 32 bits will be used (so time_t.max if it goes over and time_t.min if it goes under).

const pure nothrow timeval toTimeVal();
Returns a timeval which represents this SysTime.

Note that like all conversions in std.datetime, this is a truncating conversion.

If time_t is 32 bits, rather than 64, and the result can't fit in a 32-bit value, then the closest value that can be held in 32 bits will be used for tv_sec. (so time_t.max if it goes over and time_t.min if it goes under).

const nothrow tm toTM();
Returns a tm which represents this SysTime.

nothrow SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this 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).

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this SysTime.
allowOverflow | Whether the days should be allowed to overflow, causing the month to increment.

Examples:
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)));

nothrow void roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this SysTime. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. Rolling a SysTime 12 months gets the exact same 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.

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this SysTime.
allowOverflow | Whether the days should be allowed to overflow, causing the month to increment.

Examples:
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)));

nothrow void roll(string units)(long value);
Adds the given number of units to this SysTime. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a SysTime one year's worth of days gets the exact same SysTime.

Accepted units are "days", "minutes", "hours", "minutes", "seconds", "msecs", "usecs", and "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.

Parameters:
units | The units to add.
value | The number of units to add to this SysTime.

Examples:
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, 1, 1, 0, 0, 0));
st3.roll!"seconds"(-1);
assert(st3 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));

auto st4 = SysTime(DateTime(2010, 1, 1, 0, 0, 0),
                   FracSec.from!"usecs"(2_400));
st4.roll!"usecs"(-1_200_000);
assert(st4 == SysTime(DateTime(2010, 1, 1, 0, 0, 0),
                      FracSec.from!"usecs"(802_400)));

const pure nothrow SysTime opBinary(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this SysTime.

The legal types of arithmetic for SysTime using this operator are

SysTime + duration --> SysTime
SysTime - duration --> SysTime

Parameters:
duration The duration to add to or subtract from this SysTime.

pure nothrow SysTime opOpAssign(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this SysTime, as well as assigning the result to this SysTime.

The legal types of arithmetic for SysTime using this operator are

SysTime + duration --> SysTime
SysTime - duration --> SysTime

Parameters:
duration The duration to add to or subtract from this SysTime.

const pure nothrow Duration opBinary(string op)(in SysTime rhs);
Gives the difference between two SysTimes.

The legal types of arithmetic for SysTime using this operator are

SysTime - SysTime --> duration

const nothrow int diffMonths(in SysTime rhs);
Returns the difference between the two SysTimes in months.

To get the difference in years, subtract the year property of two SysTimes. To get the difference in days or weeks, subtract the SysTimes themselves and use the Duration that results. Because converting between months and smaller units requires a specific date (which Durations 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.

Parameters:
SysTime rhs The SysTime to subtract from this one.

Examples:
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);

const nothrow @property bool isLeapYear();
Whether this SysTime is in a leap year.

const nothrow @property DayOfWeek dayOfWeek();
Day of the week this SysTime is on.

const nothrow @property ushort dayOfYear();
Day of the year this SysTime is on.

Examples:
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);

@property void dayOfYear(int day);
Day of the year.

Parameters:
int day The day of the year to set which day of the year this SysTime is on.

const nothrow @property int dayOfGregorianCal();
The Xth day of the Gregorian Calendar that this SysTime is on.

Examples:
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);

nothrow @property void dayOfGregorianCal(int days);
The Xth day of the Gregorian Calendar that this SysTime is on. Setting this property does not affect the time portion of SysTime.

Parameters:
int days The day of the Gregorian Calendar to set this SysTime to.

Examples:
auto st = SysTime(DateTime(0, 0, 0, 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)));

const nothrow @property ubyte isoWeek();
The ISO 8601 week of the year that this SysTime is in.

See Also:
ISO Week Date.

const nothrow @property SysTime endOfMonth();
SysTime for the last day in the month that this Date is in. The time portion of endOfMonth is always 23:59:59.9999999.

Examples:
assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
       SysTime(DateTime(1999, 1, 31, 23, 59, 59),
               FracSec.from!"hnsecs"(9_999_999)));

assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0),
               FracSec.from!"msecs"(24)).endOfMonth ==
       SysTime(DateTime(1999, 2, 28, 23, 59, 59),
               FracSec.from!"hnsecs"(9_999_999)));

assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27),
               FracSec.from!"usecs"(5203)).endOfMonth ==
       SysTime(DateTime(2000, 2, 29, 23, 59, 59),
               FracSec.from!"hnsecs"(9_999_999)));

assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9),
               FracSec.from!"hnsecs"(12345)).endOfMonth ==
       SysTime(DateTime(2000, 6, 30, 23, 59, 59),
               FracSec.from!"hnsecs"(9_999_999)));

const nothrow @property ubyte daysInMonth();
The last day in the month that this SysTime is in.

Examples:
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);

const nothrow @property bool isAD();
Whether the current year is a date in A.D.

Examples:
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);

const nothrow @property long julianDay();
The julian day for this SysTime at the given time. For example, prior to noon, 1996-03-31 would be the julian day number 2450_173, so this function returns 2450_173, while from noon onward, the julian day number would be 2450_174, so this function returns 2450_174.

const nothrow @property long modJulianDay();
The modified julian day for any time on this date (since, the modified julian day changes at midnight).

const nothrow Date opCast(T)();
Returns a Date equivalent to this SysTime.

const nothrow DateTime opCast(T)();
Returns a DateTime equivalent to this SysTime.

const nothrow TimeOfDay opCast(T)();
Returns a TimeOfDay equivalent to this SysTime.

const nothrow string toISOString();
Converts this 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 SysTime's time zone is LocalTime, then TZ is empty. If its time zone is UTC, then it is "Z". Otherwise, it is the offset from UTC (e.g. +1:00 or -7:00). Note that the offset from UTC is not enough to uniquely identify the time zone.

Time zone offsets will be in the form +HH:MM or -HH:MM.

Examples:
assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
       "20100704T070612");

assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0),
               FracSec.from!"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),
               FracSec.from!"hnsecs"(520_920)).toISOString() ==
       "-00040105T000002.052092");

const nothrow string toISOExtString();
Converts this 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 SysTime's time zone is LocalTime, then TZ is empty. If its time zone is UTC, then it is "Z". Otherwise, it is the offset from UTC (e.g. +1:00 or -7:00). Note that the offset from UTC is not enough to uniquely identify the time zone.

Time zone offsets will be in the form +HH:MM or -HH:MM.

Examples:
assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
       "2010-07-04T07:06:12");

assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0),
               FracSec.from!"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),
               FracSec.from!"hnsecs"(520_920)).toISOExtString() ==
       "-0004-01-05T00:00:02.052092");

const nothrow string toSimpleString();
Converts this 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 SysTime's time zone is LocalTime, then TZ is empty. If its time zone is UTC, then it is "Z". Otherwise, it is the offset from UTC (e.g. +1:00 or -7:00). Note that the offset from UTC is not enough to uniquely identify the time zone.

Time zone offsets will be in the form +HH:MM or -HH:MM.

Examples:
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),
               FracSec.from!"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),
               FracSec.from!"hnsecs"(520_920)).toSimpleString() ==
        "-0004-Jan-05 00:00:02.052092");

const nothrow string toString();
Converts this SysTime to a string.

SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null);
Creates a 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 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 LocalTime is used. If the time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which corresponds to the given offset from UTC is used. To get the returned SysTime to be a particular time zone, pass in that time zone and the 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 +H, -H, +HH, -HH, +H:MM, -H:MM, +HH:MM, and -HH:MM.

Parameters:
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:
DateTimeException if the given string is not in the ISO format or if the resulting SysTime would not be valid.

Examples:
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), FracSec.from!"msecs"(7)));
assert(SysTime.fromISOString("00000105T230959.00002") ==
       SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"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-8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(-8))));
assert(SysTime.fromISOString("20100704T070612+8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(8))));

SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null);
Creates a 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 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 LocalTime is used. If the time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which corresponds to the given offset from UTC is used. To get the returned SysTime to be a particular time zone, pass in that time zone and the 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 +H, -H, +HH, -HH, +H:MM, -H:MM, +HH:MM, and -HH:MM.

Parameters:
isoString | 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:
DateTimeException if the given string is not in the ISO format or if the resulting SysTime would not be valid.

Examples:
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), FracSec.from!"msecs"(7)));
assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
       SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"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-8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(-8))));
assert(SysTime.fromISOExtString("2010-07-04T07:06:12+8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(8))));

SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null);
Creates a 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 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 LocalTime is used. If the time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which corresponds to the given offset from UTC is used. To get the returned SysTime to be a particular time zone, pass in that time zone and the 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 +H, -H, +HH, -HH, +H:MM, -H:MM, +HH:MM, and -HH:MM.

Parameters:
simpleString | A string formatted in the way that toSimpleString formats dates and times.
tz | The time zone to convert the given time to (no conversion occurs if null).

Throws:
DateTimeException if the given string is not in the ISO format or if the resulting SysTime would not be valid.

Examples:
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), FracSec.from!"msecs"(7)));
assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
       SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"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-8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(-8))));
assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+8:00") ==
       SysTime(DateTime(2010, 7, 4, 7, 6, 12),
               new SimpleTimeZone(dur!"hours"(8))));

static pure nothrow @property SysTime min();
Returns the SysTime farthest in the past which is representable by SysTime.

The SysTime which is returned is in UTC.

static pure nothrow @property SysTime max();
Returns the SysTime farthest in the future which is representable by SysTime.

The SysTime which is returned is in UTC.

struct Date;
Represents a date in the 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 Date is optimized for calendar-based operations.

Date uses the Proleptic Gregorian Calendar, so it assumes the Gregorian leap year calculations for its entire length. And, as per ISO 8601, it also treats 1 B.C. as year 0. So, 1 B.C. is 0, 2 B.C. is -1, etc. Use yearBC if want B.C. as a positive integer with 1 B.C. being the year prior to 1 A.D.

Year 0 is a leap year.

pure this(int year, int month, int day);
Throws:
DateTimeException if the resulting Date would not be valid.

Parameters:
int 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.
int month | Month of the year.
int day | Day of the month.

pure nothrow this(int day);
Parameters:
int day The Xth day of the Gregorian Calendar that the constructed Date will be for.

const pure nothrow int opCmp(in Date rhs);
Compares this Date with the given Date.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

const pure nothrow @property short year();
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

Examples:
assert(Date(1999, 7, 6).year == 1999);
assert(Date(2010, 10, 4).year == 2010);
assert(Date(-7, 4, 5).year == -7);

pure @property void year(int year);
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

Parameters:
int year The year to set this Date's year to.

Throws:
DateTimeException if the new year is not a leap year and the resulting date would be on February 29th.

const pure @property ushort yearBC();
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Throws:
DateTimeException if isAD is true.

Examples:
assert(Date(0, 1, 1).yearBC == 1);
assert(Date(-1, 1, 1).yearBC == 2);
assert(Date(-100, 1, 1).yearBC == 101);

pure @property void yearBC(int year);
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Parameters:
int year The year B.C. to set this Date's year to.

Throws:
DateTimeException if a non-positive value is given.

Examples:
auto date = Date(2010, 1, 1);
date.yearBC = 1;
assert(date == Date(0, 1, 1));

date.yearBC = 10;
assert(date == Date(-9, 1, 1));

const pure nothrow @property Month month();
Month of a Gregorian Year.

Examples:
assert(Date(1999, 7, 6).month == 7);
assert(Date(2010, 10, 4).month == 10);
assert(Date(-7, 4, 5).month == 4);

pure @property void month(Month month);
Month of a Gregorian Year.

Parameters:
Month month The month to set this Date's month to.

Throws:
DateTimeException if the given month is not a valid month or if the current day would not be valid in the given month.

const pure nothrow @property ubyte day();
Day of a Gregorian Month.

Examples:
assert(Date(1999, 7, 6).day == 6);
assert(Date(2010, 10, 4).day == 4);
assert(Date(-7, 4, 5).day == 5);

pure @property void day(int day);
Day of a Gregorian Month.

Parameters:
int day The day of the month to set this Date's day to.

Throws:
DateTimeException if the given day is not a valid day of the current month.

pure nothrow void add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this 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).

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this Date.
allowOverflow | Whether the day should be allowed to overflow, causing the month to increment.

Examples:
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));

pure nothrow void roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this Date. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. Rolling a Date 12 months gets the exact same 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.

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this Date.

Examples:
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));

pure nothrow void roll(string units)(long days);
Adds the given number of units to this Date. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a Date one year's worth of days gets the exact same Date.

The only accepted units are "days".

Parameters:
units | The units to add. Must be "days".
value | The number of days to add to this Date.

Examples:
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));

const pure nothrow Date opBinary(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this Date.

The legal types of arithmetic for Date using this operator are

Date + duration --> Date
Date - duration --> Date

Parameters:
duration The duration to add to or subtract from this Date.

pure nothrow Date opOpAssign(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this Date, as well as assigning the result to this Date.

The legal types of arithmetic for Date using this operator are

Date + duration --> Date
Date - duration --> Date

Parameters:
duration The duration to add to or subtract from this Date.

const pure nothrow Duration opBinary(string op)(in Date rhs);
Gives the difference between two Dates.

The legal types of arithmetic for Date using this operator are

Date - Date --> duration

const pure nothrow int diffMonths(in Date rhs);
Returns the difference between the two Dates in months.

To get the difference in years, subtract the year property of two SysTimes. To get the difference in days or weeks, subtract the SysTimes themselves and use the Duration that results. Because converting between months and smaller units requires a specific date (which Durations 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.

Parameters:
Date rhs The Date to subtract from this one.

Examples:
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);

const pure nothrow @property bool isLeapYear();
Whether this Date is in a leap year.

const pure nothrow @property DayOfWeek dayOfWeek();
Day of the week this Date is on.

const pure nothrow @property ushort dayOfYear();
Day of the year this Date is on.

Examples:
assert(Date(1999, 1, 1).dayOfYear == 1);
assert(Date(1999, 12, 31).dayOfYear == 365);
assert(Date(2000, 12, 31).dayOfYear == 366);

pure @property void dayOfYear(int day);
Day of the year.

Parameters:
int day The day of the year to set which day of the year this Date is on.

Throws:
DateTimeException if the given day is an invalid day of the year.

const pure nothrow @property int dayOfGregorianCal();
The Xth day of the Gregorian Calendar that this Date is on.

Examples:
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);

pure nothrow @property void dayOfGregorianCal(int day);
The Xth day of the Gregorian Calendar that this Date is on.

Parameters:
int day The day of the Gregorian Calendar to set this Date to.

Examples:
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));

const pure nothrow @property ubyte isoWeek();
The ISO 8601 week of the year that this Date is in.

See Also:
ISO Week Date

const pure nothrow @property Date endOfMonth();
Date for the last day in the month that this Date is in.

Examples:
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(1999, 2, 29));
assert(Date(2000, 6, 4).endOfMonth == Date(1999, 6, 30));

const pure nothrow @property ubyte daysInMonth();
The last day in the month that this Date is in.

Examples:
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);

const pure nothrow @property bool isAD();
Whether the current year is a date in A.D.

Examples:
assert(Date(1, 1, 1).isAD);
assert(Date(2010, 12, 31).isAD);
assert(!Date(0, 12, 31).isAD);
assert(!Date(-2010, 1, 1).isAD);

const pure nothrow @property long julianDay();
The julian day for this Date at noon (since the julian day changes at noon).

const pure nothrow @property long modJulianDay();
The modified julian day for any time on this date (since, the modified julian day changes at midnight).

const nothrow string toISOString();
Converts this Date to a string with the format YYYYMMDD.

Examples:
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");

const nothrow string toISOExtString();
Converts this Date to a string with the format YYYY-MM-DD.

Examples:
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");

const nothrow string toSimpleString();
Converts this Date to a string with the format YYYY-Mon-DD.

Examples:
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");

const nothrow string toString();
Converts this Date to a string.

Date fromISOString(S)(in S isoString);
Creates a Date from a string with the format YYYYMMDD. Whitespace is stripped from the given string.

Parameters:
isoString A string formatted in the ISO format for dates.

Throws:
DateTimeException if the given string is not in the ISO format or if the resulting Date would not be valid.

Examples:
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));

Date fromISOExtString(S)(in S isoExtString);
Creates a Date from a string with the format YYYY-MM-DD. Whitespace is stripped from the given string.

Parameters:
isoExtString A string formatted in the ISO Extended format for dates.

Throws:
DateTimeException if the given string is not in the ISO Extended format or if the resulting Date would not be valid.

Examples:
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));

Date fromSimpleString(S)(in S simpleString);
Creates a Date from a string with the format YYYY-Mon-DD. Whitespace is stripped from the given string.

Parameters:
simpleString A string formatted in the way that toSimpleString formats dates.

Throws:
DateTimeException if the given string is not in the correct format or if the resulting Date would not be valid.

Examples:
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));

static pure nothrow @property Date min();
Returns the Date farthest in the past which is representable by Date.

static pure nothrow @property Date max();
Returns the Date farthest in the future which is representable by Date.

struct TimeOfDay;
Represents a time of day with hours, minutes, and seconds. It uses 24 hour time.

pure this(int hour, int minute, int second = 0);
Parameters:
int hour | Hour of the day [0 - 24).
int minute | Minute of the hour [0 - 60).
int second | Second of the minute [0 - 60).

Throws:
DateTimeException if the resulting TimeOfDay would be not be valid.

const pure nothrow int opCmp(in TimeOfDay rhs);
Compares this TimeOfDay with the given TimeOfDay.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

const pure nothrow @property ubyte hour();
Hours passed midnight.

pure @property void hour(int hour);
Hours passed midnight.

Parameters:
int hour The hour of the day to set this TimeOfDay's hour to.

Throws:
DateTimeException if the given hour would result in an invalid TimeOfDay.

const pure nothrow @property ubyte minute();
Minutes passed the hour.

pure @property void minute(int minute);
Minutes passed the hour.

Parameters:
int minute The minute to set this TimeOfDay's minute to.

Throws:
DateTimeException if the given minute would result in an invalid TimeOfDay.

const pure nothrow @property ubyte second();
Seconds passed the minute.

pure @property void second(int second);
Seconds passed the minute.

Parameters:
int second The second to set this TimeOfDay's second to.

Throws:
DateTimeException if the given second would result in an invalid TimeOfDay.

pure nothrow void roll(string units)(long value);
Adds the given number of units to this TimeOfDay. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a TimeOfDay one hours's worth of minutes gets the exact same TimeOfDay.

Accepted units are "hours", "minutes", and "seconds".

Parameters:
units | The units to add.
value | The number of units to add to this TimeOfDay.

Examples:
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));

const pure nothrow TimeOfDay opBinary(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this TimeOfDay.

The legal types of arithmetic for TimeOfDay using this operator are

TimeOfDay + duration --> TimeOfDay
TimeOfDay - duration --> TimeOfDay

Parameters:
duration The duration to add to or subtract from this TimeOfDay.

pure nothrow TimeOfDay opOpAssign(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this TimeOfDay, as well as assigning the result to this TimeOfDay.

The legal types of arithmetic for TimeOfDay using this operator are

TimeOfDay + duration --> TimeOfDay
TimeOfDay - duration --> TimeOfDay

Parameters:
duration The duration to add to or subtract from this TimeOfDay.

const pure nothrow Duration opBinary(string op)(in TimeOfDay rhs);
Gives the difference between two TimeOfDays.

The legal types of arithmetic for TimeOfDay using this operator are

TimeOfDay - TimeOfDay --> duration

Parameters:
rhs The TimeOfDay to subtract from this one.

const nothrow string toISOString();
Converts this TimeOfDay to a string with the format HHMMSS.

Examples:
assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
assert(TimeOfDay(12, 30, 33).toISOString() == "123033");

const nothrow string toISOExtString();
Converts this TimeOfDay to a string with the format HH:MM:SS.

Examples:
assert(TimeOfDay(0, 0, 0).toISOExtString() == "000000");
assert(TimeOfDay(12, 30, 33).toISOExtString() == "123033");

const nothrow string toString();
Converts this TimeOfDay to a string.

TimeOfDay fromISOString(S)(in S isoString);
Creates a TimeOfDay from a string with the format HHMMSS. Whitespace is stripped from the given string.

Parameters:
isoString A string formatted in the ISO format for times.

Throws:
DateTimeException if the given string is not in the ISO format or if the resulting TimeOfDay would not be valid.

Examples:
assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));

TimeOfDay fromISOExtString(S)(in S isoExtString);
Creates a TimeOfDay from a string with the format HH:MM:SS. Whitespace is stripped from the given string.

Parameters:
isoString A string formatted in the ISO Extended format for times.

Throws:
DateTimeException if the given string is not in the ISO Extended format or if the resulting TimeOfDay would not be valid.

Examples:
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));

static pure nothrow @property TimeOfDay min();
Returns midnight.

static pure nothrow @property TimeOfDay max();
Returns one second short of midnight.

struct DateTime;
Combines the Date and 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 SysTime. SysTime has a concept of time zone and has much higher precision (hnsecs). DateTime is intended primarily for calendar-based uses rather than precise time operations.

pure nothrow this(in Date date, in TimeOfDay tod = TimeOfDay.init);
Parameters:
Date date | The date portion of DateTime.
TimeOfDay tod | The time portion of DateTime.

pure this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0);
Parameters:
int year | The year portion of the date.
int month | The month portion of the date.
int day | The day portion of the date.
int hour | The hour portion of the time;
int minute | The minute portion of the time;
int second | The second portion of the time;

const pure nothrow int opCmp(in DateTime rhs);
Compares this DateTime with the given DateTime..

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

const pure nothrow @property Date date();
The date portion of DateTime.

pure nothrow @property void date(in Date date);
The date portion of DateTime.

Parameters:
Date date The Date to set this DateTime's date portion to.

const pure nothrow @property TimeOfDay timeOfDay();
The time portion of DateTime.

pure nothrow @property void timeOfDay(in TimeOfDay tod);
The time portion of DateTime.

Parameters:
TimeOfDay tod The TimeOfDay to set this DateTime's time portion to.

const pure nothrow @property short year();
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

pure @property void year(int year);
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive are B.C.

Parameters:
int year The year to set this DateTime's year to.

Throws:
DateTimeException if the new year is not a leap year and if the resulting date would be on February 29th.

Examples:
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);

const pure @property short yearBC();
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Throws:
DateTimeException if isAD is true.

Examples:
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);

pure @property void yearBC(int year);
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.

Parameters:
int year The year B.C. to set this DateTime's year to.

Throws:
DateTimeException if a non-positive value is given.

Examples:
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)));

const pure nothrow @property Month month();
Month of a Gregorian Year.

Examples:
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);

pure @property void month(Month month);
Month of a Gregorian Year.

Parameters:
Month month The month to set this DateTime's month to.

Throws:
DateTimeException if the given month is not a valid month.

const pure nothrow @property ubyte day();
Day of a Gregorian Month.

Examples:
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);

pure @property void day(int day);
Day of a Gregorian Month.

Parameters:
int day The day of the month to set this DateTime's day to.

Throws:
DateTimeException if the given day is not a valid day of the current month.

const pure nothrow @property ubyte hour();
Hours passed midnight.

pure @property void hour(int hour);
Hours passed midnight.

Parameters:
int hour The hour of the day to set this DateTime's hour to.

Throws:
DateTimeException if the given hour would result in an invalid DateTime.

const pure nothrow @property ubyte minute();
Minutes passed the hour.

pure @property void minute(int minute);
Minutes passed the hour.

Parameters:
int minute The minute to set this DateTime's minute to.

Throws:
DateTimeException if the given minute would result in an invalid DateTime.

const pure nothrow @property ubyte second();
Seconds passed the minute.

pure @property void second(int second);
Seconds passed the minute.

Parameters:
int second The second to set this DateTime's second to.

Throws:
DateTimeException if the given seconds would result in an invalid DateTime.

pure nothrow void add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this 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).

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this DateTime.
allowOverflow | Whether the days should be allowed to overflow, causing the month to increment.

Examples:
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));

pure nothrow void roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Adds the given number of years or months to this DateTime. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. Rolling a DateTime 12 months gets the exact same 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.

Parameters:
units | The type of units to add ("years" or "months").
value | The number of months or years to add to this DateTime.
allowOverflow | Whether the days should be allowed to overflow, causing the month to increment.

Examples:
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));

pure nothrow void roll(string units)(long days);
Adds the given number of units to this DateTime. A negative number will subtract.

The difference between rolling and adding is that rolling does not affect larger units. For instance, rolling a DateTime one year's worth of days gets the exact same DateTime.

Accepted units are "days", "minutes", "hours", "minutes", and "seconds".

Parameters:
units | The units to add.
value | The number of units to add to this DateTime.

Examples:
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));

const pure nothrow DateTime opBinary(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this DateTime.

The legal types of arithmetic for DateTime using this operator are

DateTime + duration --> DateTime
DateTime - duration --> DateTime

Parameters:
duration The duration to add to or subtract from this DateTime.

pure nothrow DateTime opOpAssign(string op, D)(in D duration);
Gives the result of adding or subtracting a duration from this DateTime, as well as assigning the result to this DateTime.

The legal types of arithmetic for DateTime using this operator are

DateTime + duration --> DateTime
DateTime - duration --> DateTime

Parameters:
duration The duration to add to or subtract from this DateTime.

const pure nothrow Duration opBinary(string op)(in DateTime rhs);
Gives the difference between two DateTimes.

The legal types of arithmetic for DateTime using this operator are

DateTime - DateTime --> duration

const pure nothrow int diffMonths(in DateTime rhs);
Returns the difference between the two DateTimes in months.

To get the difference in years, subtract the year property of two SysTimes. To get the difference in days or weeks, subtract the SysTimes themselves and use the Duration that results. Because converting between months and smaller units requires a specific date (which Durations 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.

Parameters:
DateTime rhs The DateTime to subtract from this one.

Examples:
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);

const pure nothrow @property bool isLeapYear();
Whether this DateTime is in a leap year.

const pure nothrow @property DayOfWeek dayOfWeek();
Day of the week this DateTime is on.

const pure nothrow @property ushort dayOfYear();
Day of the year this DateTime is on.

Examples:
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);

pure @property void dayOfYear(int day);
Day of the year.

Parameters:
int day The day of the year to set which day of the year this DateTime is on.

const pure nothrow @property int dayOfGregorianCal();
The Xth day of the Gregorian Calendar that this DateTime is on.

Examples:
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);

pure nothrow @property void dayOfGregorianCal(int days);
The Xth day of the Gregorian Calendar that this DateTime is on. Setting this property does not affect the time portion of DateTime.

Parameters:
int days The day of the Gregorian Calendar to set this DateTime to.

Examples:
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)));

const pure nothrow @property ubyte isoWeek();
The ISO 8601 week of the year that this DateTime is in.

See Also:
ISO Week Date

const pure nothrow @property DateTime endOfMonth();
DateTime for the last day in the month that this DateTime is in. The time portion of endOfMonth is always 23:59:59.

Examples:
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)));

const pure nothrow @property ubyte daysInMonth();
The last day in the month that this DateTime is in.

Examples:
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);

const pure nothrow @property bool isAD();
Whether the current year is a date in A.D.

Examples:
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);

const pure nothrow @property long julianDay();
The julian day for this DateTime at the given time. For example, prior to noon, 1996-03-31 would be the julian day number 2450_173, so this function returns 2450_173, while from noon onward, the julian day number would be 2450_174, so this function returns 2450_174.

const pure nothrow @property long modJulianDay();
The modified julian day for any time on this date (since, the modified julian day changes at midnight).

const nothrow string toISOString();
Converts this DateTime to a string with the format YYYYMMDDTHHMMSS.

Examples:
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");

const nothrow string toISOExtString();
Converts this DateTime to a string with the format YYYY-MM-DDTHH:MM:SS.

Examples:
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");

const nothrow string toSimpleString();
Converts this DateTime to a string with the format YYYY-Mon-DD HH:MM:SS.

Examples:
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(Dte(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() ==
       "-0004-Jan-05 00:00:02");

const nothrow string toString();
Converts this DateTime to a string.

DateTime fromISOString(S)(in S isoString);
Creates a DateTime from a string with the format YYYYMMDDTHHMMSS. Whitespace is stripped from the given string.

Parameters:
isoString A string formatted in the ISO format for dates and times.

Throws:
DateTimeException if the given string is not in the ISO format or if the resulting DateTime would not be valid.

Examples:
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)));

DateTime fromISOExtString(S)(in S isoExtString);
Creates a DateTime from a string with the format YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string.

Parameters:
isoString A string formatted in the ISO Extended format for dates and times.

Throws:
DateTimeException if the given string is not in the ISO Extended format or if the resulting DateTime would not be valid.

Examples:
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)));

DateTime fromSimpleString(S)(in S simpleString);
Creates a DateTime from a string with the format YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string.

Parameters:
simpleString A string formatted in the way that toSimpleString formats dates and times.

Throws:
DateTimeException if the given string is not in the correct format or if the resulting DateTime would not be valid.

Examples:
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)));

static pure nothrow @property DateTime min();
Returns the DateTime farthest in the past which is representable by DateTime.

static pure nothrow @property DateTime max();
Returns the DateTime farthest in the future which is representable by DateTime.

struct Interval(TP);
Represents an interval of time.

An 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.

[January 5th, 2010 - March 10th, 2010)
[05:00:30 - 12:00:00)
[1982-01-04T08:59:00 - 2010-07-04T12:00:00)

A range can be obtained from an Interval, allowing iteration over that interval, with the exact time points which are iterated over depending on the function which generates the range.

pure this(U)(in TP begin, in U end);
Parameters:
begin | The time point which begins the interval.
end | The time point which ends (but is not included in) the interval.

Throws:
DateTimeException if end is before begin.

Examples:
Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));

pure this(D)(in TP begin, in D duration);
Parameters:
begin | The time point which begins the interval.
duration | The duration from the starting point to the end point.

Throws:
DateTimeException if the resulting end is before begin.

Examples:
assert(Interval!Date(Date(1996, 1, 2), dur!"years"(3)) ==
       Interval!Date(Date(1996, 1, 2), Date(1999, 1, 2)));

pure nothrow Interval opAssign(ref const Interval rhs);
Parameters:
Interval rhs The Interval to assign to this one.

pure nothrow Interval opAssign(Interval rhs);
Parameters:
Interval rhs The Interval to assign to this one.

const pure nothrow TP begin();
The starting point of the interval. It is included in the interval.

Examples:
assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin ==
       Date(1996, 1, 2));

pure void begin(TP timePoint);
The starting point of the interval. It is included in the interval.

Parameters:
TP timePoint The time point to set begin to.

Throws:
DateTimeException if the resulting interval would be invalid.

const pure nothrow TP end();
The end point of the interval. It is excluded from the interval.

Examples:
assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end ==
       Date(2012, 3, 1));

pure void end(TP timePoint);
The end point of the interval. It is excluded from the interval.

Parameters:
TP timePoint The time point to set end to.

Throws:
DateTimeException if the resulting interval would be invalid.

const pure nothrow typeof(end - begin) length();
Returns the duration between begin and end.

Examples:
assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length ==
       dur!"days"(5903));

const pure nothrow bool empty();
Whether the interval's length is 0, that is, whether begin == end.

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

const pure bool contains(in TP timePoint);
Whether the given time point is within this interval.

Parameters:
TP timePoint The time point to check for inclusion in this interval.

Throws:
DateTimeException if this interval is empty.

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

const pure bool contains(in Interval interval);
Whether the given interval is completely within this interval.

Parameters:
Interval interval The interval to check for inclusion in this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure bool contains(in PosInfInterval!(TP) interval);
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.

Parameters:
PosInfInterval!(TP) interval The interval to check for inclusion in this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
            PosInfInterval!Date(Date(1999, 5, 4))));

const pure bool contains(in NegInfInterval!(TP) interval);
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.

Parameters:
NegInfInterval!(TP) interval The interval to check for inclusion in this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(
            NegInfInterval!Date(Date(1996, 5, 4))));

const pure bool isBefore(in TP timePoint);
Whether this interval is before the given time point.

Parameters:
TP timePoint The time point to check whether this interval is before it.

Throws:
DateTimeException if this interval is empty.

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

const pure bool isBefore(in Interval interval);
Whether this interval is before the given interval and does not intersect with it.

Parameters:
Interval interval The interval to check for against this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure bool isBefore(in PosInfInterval!(TP) interval);
Whether this interval is before the given interval and does not intersect with it.

Parameters:
PosInfInterval!(TP) interval The interval to check for against this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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))));

const pure bool isBefore(in NegInfInterval!(TP) interval);
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.

Parameters:
NegInfInterval!(TP) interval The interval to check for against this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(
            NegInfInterval!Date(Date(1996, 5, 4))));

const pure bool isAfter(in TP timePoint);
Whether this interval is after the given time point.

Parameters:
TP timePoint The time point to check whether this interval is after it.

Throws:
DateTimeException if this interval is empty.

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

const pure bool isAfter(in Interval interval);
Whether this interval is after the given interval and does not intersect it.

Parameters:
Interval interval The interval to check against this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure bool isAfter(in PosInfInterval!(TP) interval);
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.

Parameters:
PosInfInterval!(TP) interval The interval to check against this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
            PosInfInterval!Date(Date(1999, 5, 4))));

const pure bool isAfter(in NegInfInterval!(TP) interval);
Whether this interval is after the given interval and does not intersect it.

Parameters:
NegInfInterval!(TP) interval The interval to check against this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(
            NegInfInterval!Date(Date(1996, 1, 2))));

const pure bool intersects(in Interval interval);
Whether the given interval overlaps this interval.

Parameters:
Interval interval The interval to check for intersection with this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure bool intersects(in PosInfInterval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
PosInfInterval!(TP) interval The interval to check for intersection with this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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))));

const pure bool intersects(in NegInfInterval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
NegInfInterval!(TP) interval The interval to check for intersection with this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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))));

const Interval intersection(in Interval interval);
Returns the intersection of two intervals

Parameters:
Interval interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect or if either interval is empty.

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

const Interval intersection(in PosInfInterval!(TP) interval);
Returns the intersection of two intervals

Parameters:
PosInfInterval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect or if this interval is empty.

Examples:
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)));

const Interval intersection(in NegInfInterval!(TP) interval);
Returns the intersection of two intervals

Parameters:
NegInfInterval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect or if this interval is empty.

Examples:
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)));

const pure bool isAdjacent(in Interval interval);
Whether the given interval is adjacent to this interval.

Parameters:
Interval interval The interval to check whether its adjecent to this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure bool isAdjacent(in PosInfInterval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
PosInfInterval!(TP) interval The interval to check whether its adjecent to this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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))));

const pure bool isAdjacent(in NegInfInterval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
NegInfInterval!(TP) interval The interval to check whether its adjecent to this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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))));

const Interval merge(in Interval interval);
Returns the union of two intervals

Parameters:
Interval interval The interval to merge with this interval.

Throws:
DateTimeException if the two intervals do not intersect and are not adjacent or if either interval is empty.

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

const PosInfInterval!(TP) merge(in PosInfInterval!(TP) interval);
Returns the union of two intervals

Parameters:
PosInfInterval!(TP) interval The interval to merge with this interval.

Throws:
DateTimeException if the two intervals do not intersect and are not adjacent or if this interval is empty.

Examples:
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)));

const NegInfInterval!(TP) merge(in NegInfInterval!(TP) interval);
Returns the union of two intervals

Parameters:
NegInfInterval!(TP) interval The interval to merge with this interval.

Throws:
DateTimeException if the two intervals do not intersect and are not adjacent or if this interval is empty.

Examples:
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)));

const pure Interval span(in Interval interval);
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.

Parameters:
Interval interval The interval to create a span together with this interval.

Throws:
DateTimeException if either interval is empty.

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

const pure PosInfInterval!(TP) span(in PosInfInterval!(TP) interval);
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.

Parameters:
PosInfInterval!(TP) interval The interval to create a span together with this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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)));

const pure NegInfInterval!(TP) span(in NegInfInterval!(TP) interval);
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.

Parameters:
NegInfInterval!(TP) interval The interval to create a span together with this interval.

Throws:
DateTimeException if this interval is empty.

Examples:
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)));

pure void shift(D)(D duration);
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 begin += duration and end += duration.

Parameters:
duration The duration to shift the interval by.

Throws:
DateTimeException this interval is empty or if the resulting interval would be invalid.

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

void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
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 add!"years"() and then add!"months"() on begin and end with the given number of years and months.

Parameters:
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 begin and end, causing their month to increment.

Throws:
DateTimeException if this interval is empty or if the resulting interval would be invalid.

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

pure void expand(D)(D duration, Direction dir = Direction.both);
Expands the interval forwards and/or backwards in time. Effectively, it does begin -= duration and/or end += duration. Whether it expands forwards and/or backwards in time is determined by dir.

Parameters:
duration | The duration to expand the interval by.
dir | The direction in time to expand the interval.

Throws:
DateTimeException this interval is empty or if the resulting interval would be invalid.

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

void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes, Direction dir = Direction.both);
Expands the interval forwards and/or backwards in time. Effectively, it subtracts the given number of months/years from begin and adds them to end. Whether it expands forwards and/or backwards in time is determined by dir.

Parameters:
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 begin and end, causing their month to increment.

Throws:
DateTimeException if this interval is empty or if the resulting interval would be invalid.

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

const IntervalRange!(TP, Direction.fwd) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no);
Returns a range which iterates forward over the interval, starting at begin, using func to generate each successive time point.

The range's front is the interval's begin. func is used to generate the next front when popFront is called. If popFirst is PopFirst.yes, then popFront is called before the range is returned (so that front is a time point which func would generate).

If func ever generates a time point less than or equal to the current front of the range, then a DateTimeException will be thrown. The range will be empty and iteration complete when func generates a time point equal to or beyond the end of the interval.

There are helper functions in this module which generate common delegates to pass to fwdRange. Their documentation starts with "Range-generating function," making them easily searchable.

Parameters:
TP delegate(in TP) func | The function used to generate the time points of the range over the interval.
PopFirst popFirst | Whether popFront should be called on the range before returning it.

Throws:
DateTimeException if this interval is empty.

Warning:
func must be logically pure. Ideally, func would be a function pointer to a pure function, but forcing 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 fwdRange, func must be a delegate.

If func retains state which changes as it is called, then some algorithms will not work correctly, because the range's 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 fwdRange. If 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.

Examples:
auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
auto func = (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);

const IntervalRange!(TP, Direction.bwd) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no);
Returns a range which iterates backwards over the interval, starting at end, using func to generate each successive time point.

The range's front is the interval's end. func is used to generate the next front when popFront is called. If popFirst is PopFirst.yes, then popFront is called before the range is returned (so that front is a time point which func would generate).

If func ever generates a time point greater than or equal to the current front of the range, then a DateTimeException will be thrown. The range will be empty and iteration complete when func generates a time point equal to or less than the begin of the interval.

There are helper functions in this module which generate common delegates to pass to bwdRange. Their documentation starts with "Range-generating function," making them easily searchable.

Parameters:
TP delegate(in TP) func | The function used to generate the time points of the range over the interval.
PopFirst popFirst | Whether popFront should be called on the range before returning it.

Throws:
DateTimeException if this interval is empty.

Warning:
func must be logically pure. Ideally, func would be a function pointer to a pure function, but forcing 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 fwdRange, func must be a delegate.

If func retains state which changes as it is called, then some algorithms will not work correctly, because the range's 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 fwdRange. If 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.

Examples:
auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
auto func = (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);

const nothrow string toString();
Converts this interval to a string.

struct PosInfInterval(TP);
Represents an interval of time which has positive infinity as its end point.

Any ranges which iterate over a PosInfInterval are infinite. So, the main purpose of using PosInfInterval is to create an infinite range which starts at a fixed point in time and goes to positive infinity.

pure nothrow this(in TP begin);
Parameters:
TP begin The time point which begins the interval.

Examples:
auto interval = PosInfInterval!Date(Date(1996, 1, 2));

pure nothrow PosInfInterval opAssign(ref const PosInfInterval rhs);
Parameters:
PosInfInterval rhs The PosInfInterval to assign to this one.

pure nothrow PosInfInterval opAssign(PosInfInterval rhs);
Parameters:
PosInfInterval rhs The PosInfInterval to assign to this one.

const pure nothrow TP begin();
The starting point of the interval. It is included in the interval.

Examples:
assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2));

pure nothrow void begin(TP timePoint);
The starting point of the interval. It is included in the interval.

Parameters:
TP timePoint The time point to set begin to.

const pure nothrow bool empty();
Whether the interval's length is 0. Always returns false.

Examples:
assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty);

const pure nothrow bool contains(TP timePoint);
Whether the given time point is within this interval.

Parameters:
TP timePoint The time point to check for inclusion in this interval.

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

const pure bool contains(in Interval!(TP) interval);
Whether the given interval is completely within this interval.

Parameters:
Interval!(TP) interval The interval to check for inclusion in this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool contains(in PosInfInterval interval);
Whether the given interval is completely within this interval.

Parameters:
PosInfInterval interval The interval to check for inclusion in this interval.

Examples:
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))));

const pure nothrow bool contains(in NegInfInterval!(TP) interval);
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.

Parameters:
NegInfInterval!(TP) interval The interval to check for inclusion in this interval.

Examples:
assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(
            NegInfInterval!Date(Date(1996, 5, 4))));

const pure nothrow bool isBefore(in TP timePoint);
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.

Parameters:
TP timePoint The time point to check whether this interval is before it.

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

const pure bool isBefore(in Interval!(TP) interval);
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.

Parameters:
Interval!(TP) interval The interval to check for against this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool isBefore(in PosInfInterval interval);
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.

Parameters:
PosInfInterval interval The interval to check for against this interval.

Examples:
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))));

const pure nothrow bool isBefore(in NegInfInterval!(TP) interval);
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.

Parameters:
NegInfInterval!(TP) interval The interval to check for against this interval.

Examples:
assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(
            NegInfInterval!Date(Date(1996, 5, 4))));

const pure nothrow bool isAfter(in TP timePoint);
Whether this interval is after the given time point.

Parameters:
TP timePoint The time point to check whether this interval is after it.

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

const pure bool isAfter(in Interval!(TP) interval);
Whether this interval is after the given interval and does not intersect it.

Parameters:
Interval!(TP) interval The interval to check against this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool isAfter(in PosInfInterval interval);
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.

Parameters:
PosInfInterval interval The interval to check against this interval.

Examples:
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))));

const pure nothrow bool isAfter(in NegInfInterval!(TP) interval);
Whether this interval is after the given interval and does not intersect it.

Parameters:
NegInfInterval!(TP) interval The interval to check against this interval.

Examples:
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))));

const pure bool intersects(in Interval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
Interval!(TP) interval The interval to check for intersection with this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool intersects(in PosInfInterval interval);
Whether the given interval overlaps this interval.

Always returns true because two intervals going to positive infinity always overlap.

Parameters:
PosInfInterval interval The interval to check for intersection with this interval.

Examples:
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))));

const pure nothrow bool intersects(in NegInfInterval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
NegInfInterval!(TP) interval The interval to check for intersection with this interval.

Examples:
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))));

const Interval!(TP) intersection(in Interval!(TP) interval);
Returns the intersection of two intervals

Parameters:
Interval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect or if the given interval is empty.

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

const pure nothrow PosInfInterval intersection(in PosInfInterval interval);
Returns the intersection of two intervals

Parameters:
PosInfInterval interval The interval to intersect with this interval.

Examples:
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)));

const Interval!(TP) intersection(in NegInfInterval!(TP) interval);
Returns the intersection of two intervals

Parameters:
NegInfInterval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect.

Examples:
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)));

const pure bool isAdjacent(in Interval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
Interval!(TP) interval The interval to check whether its adjecent to this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool isAdjacent(in PosInfInterval interval);
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.

Parameters:
PosInfInterval interval The interval to check whether its adjecent to this interval.

Examples:
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))));

const pure nothrow bool isAdjacent(in NegInfInterval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
NegInfInterval!(TP) interval The interval to check whether its adjecent to this interval.

Examples:
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))));

const PosInfInterval merge(in Interval!(TP) interval);
Returns the union of two intervals

Parameters:
Interval!(TP) interval The interval to merge with this interval.

Throws:
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 merge which takes a NegInfInterval, because an interval going from negative infinity to positive infinity is not possible.

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

const pure nothrow PosInfInterval merge(in PosInfInterval interval);
Returns the union of two intervals

Parameters:
PosInfInterval interval The interval to merge with this interval.

Note:
There is no overload for merge which takes a NegInfInterval, because an interval going from negative infinity to positive infinity is not possible.

Examples:
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)));

const pure PosInfInterval span(in Interval!(TP) interval);
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.

Parameters:
Interval!(TP) interval The interval to create a span together with this interval.

Throws:
DateTimeException if the given interval is empty.

Note:
There is no overload for span which takes a NegInfInterval, because an interval going from negative infinity to positive infinity is not possible.

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

const pure nothrow PosInfInterval span(in PosInfInterval interval);
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.

Parameters:
PosInfInterval interval The interval to create a span together with this interval.

Note:
There is no overload for span which takes a NegInfInterval, because an interval going from negative infinity to positive infinity is not possible.

Examples:
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)));

pure nothrow void shift(D)(D duration);
Shifts the 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 begin += duration.

Parameters:
duration The duration to shift the interval by.

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

void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Shifts the 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 begin. It effectively calls add!"years"() and then add!"months"() on begin with the given number of years and months.

Parameters:
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 begin, causing its month to increment.

Throws:
DateTimeException if this interval is empty or if the resulting interval would be invalid.

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

pure nothrow void expand(D)(D duration);
Expands the interval backwards in time. Effectively, it does begin -= duration.

Parameters:
duration | The duration to expand the interval by.
dir | The direction in time to expand the interval.

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

void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Expands the interval forwards and/or backwards in time. Effectively, it subtracts the given number of months/years from begin.

Parameters:
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 begin, causing its month to increment.

Throws:
DateTimeException if this interval is empty or if the resulting interval would be invalid.

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

const PosInfIntervalRange!(TP) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no);
Returns a range which iterates forward over the interval, starting at begin, using func to generate each successive time point.

The range's front is the interval's begin. func is used to generate the next front when popFront is called. If popFirst is PopFirst.yes, then popFront is called before the range is returned (so that front is a time point which func would generate).

If func ever generates a time point less than or equal to the current front of the range, then a DateTimeException will be thrown.

There are helper functions in this module which generate common delegates to pass to fwdRange. Their documentation starts with "Range-generating function," to make them easily searchable.

Parameters:
TP delegate(in TP) func | The function used to generate the time points of the range over the interval.
PopFirst popFirst | Whether popFront should be called on the range before returning it.

Throws:
DateTimeException if this interval is empty.

Warning:
func must be logically pure. Ideally, func would be a function pointer to a pure function, but forcing 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 fwdRange, func must be a delegate.

If func retains state which changes as it is called, then some algorithms will not work correctly, because the range's 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 fwdRange. If 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.

Examples:
auto interval = PosInfInterval!Date(Date(2010, 9, 1));
auto func = (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);

const nothrow string toString();
Converts this interval to a string.

struct NegInfInterval(TP);
Represents an interval of time which has negative infinity as its starting point.

Any ranges which iterate over a NegInfInterval are infinite. So, the main purpose of using NegInfInterval is to create an infinite range which starts at negative infinity and goes to a fixed end point. Iterate over it in reverse.

pure nothrow this(in TP end);
Parameters:
begin The time point which begins the interval.

Examples:
auto interval = PosInfInterval!Date(Date(1996, 1, 2));

pure nothrow NegInfInterval opAssign(ref const NegInfInterval rhs);
Parameters:
NegInfInterval rhs The NegInfInterval to assign to this one.

pure nothrow NegInfInterval opAssign(NegInfInterval rhs);
Parameters:
NegInfInterval rhs The NegInfInterval to assign to this one.

const pure nothrow TP end();
The end point of the interval. It is excluded from the interval.

Examples:
assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1));

pure nothrow void end(TP timePoint);
The end point of the interval. It is excluded from the interval.

Parameters:
TP timePoint The time point to set end to.

const pure nothrow bool empty();
Whether the interval's length is 0. Always returns false.

Examples:
assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty);

const pure nothrow bool contains(TP timePoint);
Whether the given time point is within this interval.

Parameters:
TP timePoint The time point to check for inclusion in this interval.

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

const pure bool contains(in Interval!(TP) interval);
Whether the given interval is completely within this interval.

Parameters:
Interval!(TP) interval The interval to check for inclusion in this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool contains(in PosInfInterval!(TP) interval);
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.

Parameters:
PosInfInterval!(TP) interval The interval to check for inclusion in this interval.

Examples:
assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(
            PosInfInterval!Date(Date(1999, 5, 4))));

const pure nothrow bool contains(in NegInfInterval interval);
Whether the given interval is completely within this interval.

Parameters:
NegInfInterval interval The interval to check for inclusion in this interval.

Examples:
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))));

const pure nothrow bool isBefore(in TP timePoint);
Whether this interval is before the given time point.

Parameters:
TP timePoint The time point to check whether this interval is before it.

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

const pure bool isBefore(in Interval!(TP) interval);
Whether this interval is before the given interval and does not intersect it.

Parameters:
Interval!(TP) interval The interval to check for against this interval.

Throws:
DateTimeException if the given interval is empty

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

const pure nothrow bool isBefore(in PosInfInterval!(TP) interval);
Whether this interval is before the given interval and does not intersect it.

Parameters:
PosInfInterval!(TP) interval The interval to check for against this interval.

Examples:
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))));

const pure nothrow bool isBefore(in NegInfInterval interval);
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.

Parameters:
NegInfInterval interval The interval to check for against this interval.

Examples:
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))));

const pure nothrow bool isAfter(in TP timePoint);
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.

Parameters:
TP timePoint The time point to check whether this interval is after it.

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

const pure bool isAfter(in Interval!(TP) interval);
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.

Parameters:
Interval!(TP) interval The interval to check against this interval.

Throws:
DateTimeException if the given interval is empty.

Examples:
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))));

const pure nothrow bool isAfter(in PosInfInterval!(TP) interval);
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.

Parameters:
PosInfInterval!(TP) interval The interval to check against this interval.

Examples:
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))));

const pure nothrow bool isAfter(in NegInfInterval interval);
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.

Parameters:
NegInfInterval interval The interval to check against this interval.

Examples:
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))));

const pure bool intersects(in Interval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
Interval!(TP) interval The interval to check for intersection with this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool intersects(in PosInfInterval!(TP) interval);
Whether the given interval overlaps this interval.

Parameters:
PosInfInterval!(TP) interval The interval to check for intersection with this interval.

Examples:
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))));

const pure nothrow bool intersects(in NegInfInterval!(TP) interval);
Whether the given interval overlaps this interval.

Always returns true because two intervals beginning at negative infinity always overlap.

Parameters:
NegInfInterval!(TP) interval The interval to check for intersection with this interval.

Examples:
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))));

const Interval!(TP) intersection(in Interval!(TP) interval);
Returns the intersection of two intervals

Parameters:
Interval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect or if the given interval is empty.

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

const Interval!(TP) intersection(in PosInfInterval!(TP) interval);
Returns the intersection of two intervals

Parameters:
PosInfInterval!(TP) interval The interval to intersect with this interval.

Throws:
DateTimeException if the two intervals do not intersect.

Examples:
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)));

const nothrow NegInfInterval intersection(in NegInfInterval interval);
Returns the intersection of two intervals

Parameters:
NegInfInterval interval The interval to intersect with this interval.

Examples:
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)));

const pure bool isAdjacent(in Interval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
Interval!(TP) interval The interval to check whether its adjecent to this interval.

Throws:
DateTimeException if the given interval is empty.

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

const pure nothrow bool isAdjacent(in PosInfInterval!(TP) interval);
Whether the given interval is adjacent to this interval.

Parameters:
PosInfInterval!(TP) interval The interval to check whether its adjecent to this interval.

Examples:
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))));

const pure nothrow bool isAdjacent(in NegInfInterval interval);
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.

Parameters:
NegInfInterval interval The interval to check whether its adjecent to this interval.

Examples:
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))));

const NegInfInterval merge(in Interval!(TP) interval);
Returns the union of two intervals

Parameters:
Interval!(TP) interval The interval to merge with this interval.

Throws:
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 merge which takes a PosInfInterval, because an interval going from negative infinity to positive infinity is not possible.

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

const pure nothrow NegInfInterval merge(in NegInfInterval interval);
Returns the union of two intervals

Parameters:
NegInfInterval interval The interval to merge with this interval.

Note:
There is no overload for merge which takes a PosInfInterval, because an interval going from negative infinity to positive infinity is not possible.

Examples:
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)));

const pure NegInfInterval span(in Interval!(TP) interval);
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.

Parameters:
Interval!(TP) interval The interval to create a span together with this interval.

Throws:
DateTimeException if the given interval is empty.

Note:
There is no overload for span which takes a PosInfInterval, because an interval going from negative infinity to positive infinity is not possible.

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

const pure nothrow NegInfInterval span(in NegInfInterval interval);
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.

Parameters:
NegInfInterval interval The interval to create a span together with this interval.

Note:
There is no overload for span which takes a PosInfInterval, because an interval going from negative infinity to positive infinity is not possible.

Examples:
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)));

pure nothrow void shift(D)(D duration);
Shifts the 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 end += duration.

Parameters:
duration The duration to shift the interval by.

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

void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Shifts the 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 add!"years"() and then add!"months"() on end with the given number of years and months.

Parameters:
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 end, causing its month to increment.

Throws:
DateTimeException if empty is true or if the resulting interval would be invalid.

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

pure nothrow void expand(D)(D duration);
Expands the interval forwards in time. Effectively, it does end += duration.

Parameters:
duration | The duration to expand the interval by.
dir | The direction in time to expand the interval.

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

void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes);
Expands the interval forwards and/or backwards in time. Effectively, it adds the given number of months/years to end.

Parameters:
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 end, causing their month to increment.

Throws:
DateTimeException if empty is true or if the resulting interval would be invalid.

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

const NegInfIntervalRange!(TP) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no);
Returns a range which iterates backwards over the interval, starting at end, using func to generate each successive time point.

The range's front is the interval's end. func is used to generate the next front when popFront is called. If popFirst is PopFirst.yes, then popFront is called before the range is returned (so that front is a time point which func would generate).

If func ever generates a time point greater than or equal to the current front of the range, then a DateTimeException will be thrown.

There are helper functions in this module which generate common delegates to pass to bwdRange. Their documentation starts with "Range-generating function," to make them easily searchable.

Parameters:
TP delegate(in TP) func | The function used to generate the time points of the range over the interval.
PopFirst popFirst | Whether popFront should be called on the range before returning it.

Throws:
DateTimeException if this interval is empty.

Warning:
func must be logically pure. Ideally, func would be a function pointer to a pure function, but forcing 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 fwdRange, func must be a delegate.

If func retains state which changes as it is called, then some algorithms will not work correctly, because the range's 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 fwdRange. If 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.

Examples:
auto interval = NegInfInterval!Date(Date(2010, 9, 9));
auto func = (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);

const nothrow string toString();
Converts this interval to a string.

nothrow TP delegate(in TP) everyDayOfWeek(TP, Direction dir = Direction.fwd)(DayOfWeek dayOfWeek);
Range-generating function.

Returns a delegate which returns the next time point with the given 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 DayOfWeek.mon to everyDayOfWeek would result in a delegate which could be used to iterate over all of the Mondays in a range.

Parameters:
dir | The direction to iterate in. If passing the return value to fwdRange, use Direction.fwd. If passing it to bwdRange, use Direction.bwd.
dayOfWeek | The week that each time point in the range will be.

Examples:
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);

TP delegate(in TP) everyMonth(TP, Direction dir = Direction.fwd)(int month);
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 Month.dec to 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, AllowDayOverflow.no is always used when calculating the next time point.

Parameters:
dir | The direction to iterate in. If passing the return value to fwdRange, use Direction.fwd. If passing it to bwdRange, use Direction.bwd.
month | The month that each time point in the range will be in.

Examples:
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);

nothrow TP delegate(in TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration);
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 dur!"days"(3) to everyDuration would result in a delegate which could be used to iterate over a range of days which are each 3 days apart.

Parameters:
dir | The direction to iterate in. If passing the return value to fwdRange, use Direction.fwd. If passing it to bwdRange, use Direction.bwd.
duration | The duration which separates each successive time point in the range.

Examples:
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);

nothrow 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));
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 everyDuration and the version which just takes a Duration is that this one also takes the number of years and months (along with an AllowDayOverflow to indicate whether adding years and months should allow the days to overflow).

Note that if iterating forward, add!"years"() is called on the given time point, then add!"months"(), and finally the duration is added to it. However, if iterating backwards, the duration is added first, then add!"months"() is called, and finally 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 AllowDayOverflow.yes or 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 begin).

Parameters:
dir | The direction to iterate in. If passing the return value to fwdRange, use Direction.fwd. If passing it to bwdRange, use 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 begin and end, causing their month to increment.
duration | The duration to add to the time point passed to the delegate.

Examples:
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);

struct IntervalRange(TP, Direction dir) if (isTimePoint!(TP) && dir != Direction.both);
A range over an Interval.

IntervalRange is only ever constructed by Interval. However, when it is constructed, it is given a function, func, which is used to generate the time points which are iterated over. 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 Interval!Date, pass a function to Interval's fwdRange where that function took a Date and returned a Date which was one day later. That function would then be used by IntervalRange's popFront to iterate over the Dates in the interval.

If dir == Direction.fwd, then a range iterates forward in time, whereas if dir == Direction.bwd, then it iterates backwards in time. So, if dir == Direction.fwd then front == interval.begin, whereas if dir == Direction.bwd then front == interval.end. func must generate a time point going in the proper direction of iteration, or a DateTimeException will be thrown. So, to iterate forward in time, the time point that func generates must be later in time than the one passed to it. If it's either identical or earlier in time, then a 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 end, then front becomes end. If iterating backwards, and the generated time point is before begin, then front becomes begin. In either case, the range would then be empty.

Also note that while normally the begin of an interval is included in it and its end is excluded from it, if dir == Direction.bwd, then begin is treated as excluded and end is treated as included. This allows for the same behavior in both directions. This works because none of Interval's functions which care about whether begin or end is included or excluded are ever called by IntervalRange. interval returns a normal interval, regardless of whether dir == Direction.fwd or if dir == Direction.bwd, so any Interval functions which are called on it which care about whether begin or end are included or excluded will treat begin as included and end as excluded.

pure nothrow IntervalRange opAssign(ref IntervalRange rhs);
Parameters:
IntervalRange rhs The IntervalRange to assign to this one.

const pure nothrow bool empty();
Whether this IntervalRange is empty.

const pure TP front();
The first time point in the range.

Throws:
DateTimeException if the range is empty.

void popFront();
Pops front from the range, using func to generate the next time point in the range. If the generated time point is beyond the edge of the range, then 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 end, then front is set to end. If iterating backwards, and the generated time point is less than the interval's begin, then front is set to begin.

Throws:
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 front, or if iterating backwards and the generated time point is after front).

pure nothrow IntervalRange save();
Returns a copy of this.

const pure nothrow Interval!(TP) interval();
The interval that this IntervalRange currently covers.

pure nothrow @property TP delegate(in TP) func();
The function used to generate the next time point in the range.

const pure nothrow Direction direction();
The Direction that this range iterates in.

struct PosInfIntervalRange(TP) if (isTimePoint!(TP));
A range over a PosInfInterval. It is an infinite range.

PosInfIntervalRange is only ever constructed by PosInfInterval. However, when it is constructed, it is given a function, func, which is used to generate the time points which are iterated over. 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 PosInfInterval!Date, pass a function to PosInfInterval's fwdRange where that function took a Date and returned a Date which was one day later. That function would then be used by PosInfIntervalRange's popFront to iterate over the Dates in the interval - though obviously, since the range is infinite, use a function such as std.range.take with it rather than iterating over all of the dates.

As the interval goes to positive infinity, the range is always iterated over forwards, never backwards. func must generate a time point going in the proper direction of iteration, or a DateTimeException will be thrown. So, the time points that func generates must be later in time than the one passed to it. If it's either identical or earlier in time, then a DateTimeException will be thrown.

pure nothrow PosInfIntervalRange opAssign(ref PosInfIntervalRange rhs);
Parameters:
PosInfIntervalRange rhs The PosInfIntervalRange to assign to this one.

bool empty;
This is an infinite range, so it is never empty.

const pure nothrow TP front();
The first time point in the range.

void popFront();
Pops front from the range, using func to generate the next time point in the range.

Throws:
DateTimeException if the generated time point is less than front.

pure nothrow PosInfIntervalRange save();
Returns a copy of this.

const pure nothrow PosInfInterval!(TP) interval();
The interval that this range currently covers.

pure nothrow @property TP delegate(in TP) func();
The function used to generate the next time point in the range.

struct NegInfIntervalRange(TP) if (isTimePoint!(TP));
A range over a NegInfInterval. It is an infinite range.

NegInfIntervalRange is only ever constructed by NegInfInterval. However, when it is constructed, it is given a function, func, which is used to generate the time points which are iterated over. 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 NegInfInterval!Date, pass a function to NegInfInterval's bwdRange where that function took a Date and returned a Date which was one day earlier. That function would then be used by NegInfIntervalRange's popFront to iterate over the Dates in the interval - though obviously, since the range is infinite, use a function such as std.range.take with it rather than iterating over all of the dates.

As the interval goes to negative infinity, the range is always iterated over backwards, never forwards. func must generate a time point going in the proper direction of iteration, or a DateTimeException will be thrown. So, the time points that func generates must be earlier in time than the one passed to it. If it's either identical or later in time, then a DateTimeException will be thrown.

Also note that while normally the end of an interval is excluded from it, NegInfIntervalRange treats it as if it were included. This allows for the same behavior as with PosInfIntervalRange. This works because none of NegInfInterval's functions which care about whether end is included or excluded are ever called by NegInfIntervalRange. interval returns a normal interval, so any NegInfInterval functions which are called on it which care about whether end is included or excluded will treat end as excluded.

pure nothrow NegInfIntervalRange opAssign(ref NegInfIntervalRange rhs);
Parameters:
NegInfIntervalRange rhs The NegInfIntervalRange to assign to this one.

bool empty;
This is an infinite range, so it is never empty.

const pure nothrow TP front();
The first time point in the range.

void popFront();
Pops front from the range, using func to generate the next time point in the range.

Throws:
DateTimeException if the generated time point is greater than front.

pure nothrow NegInfIntervalRange save();
Returns a copy of this.

const pure nothrow NegInfInterval!(TP) interval();
The interval that this range currently covers.

pure nothrow @property TP delegate(in TP) func();
The function used to generate the next time point in the range.

abstract class TimeZone;
Represents a time zone. It is used with SysTime to indicate the time zone of a SysTime.

const nothrow @property string name();
The name of the time zone per the TZ Database. This is the name used to get a TimeZone by name with TimeZone.getTimeZone.

See Also:
Wikipedia entry on TZ Database
List of Time Zones

const nothrow @property string stdName();
Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST is 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.

const nothrow @property string dstName();
Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST 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.

abstract const nothrow @property bool hasDST();
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 hasDST because the time zone did at some point have DST.

abstract const nothrow bool dstInEffect(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be checked for DST in this time zone.

abstract const nothrow long utcToTZ(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

abstract const nothrow long tzToUTC(long adjTime);
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).

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

const nothrow Duration utcOffsetAt(long stdTime);
Returns what the offset from UTC is at the given std time. It includes the DST offset in effect at that time (if any).

Parameters:
long stdTime The UTC time for which to get the offset from UTC for this time zone.

static immutable(TimeZone) getTimeZone(string name);
Returns a TimeZone with the give name per the TZ Database.

This returns a PosixTimeZone on Posix systems and a WindowsTimeZone on Windows systems. For PosixTimeZone on Windows, call 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 WindowsTimeZone.getTimeZone. This function allows for the same time zone names on both Windows and Posix systems.

See Also:
Wikipedia entry on TZ Database
List of Time Zones
Windows <-> TZ Database Name Conversion Table

Parameters:
string name The TZ Database name of the desired time zone

Throws:
DateTimeException if the given time zone could not be found.

Examples:
auto tz = TimeZone.getTimeZone("America/Los_Angeles");

static string[] getInstalledTZNames(string subName = "");
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 windowsTZNameToTZDatabaseName. To get the actual Windows time zone names, use WindowsTimeZone.getInstalledTZNames directly.

Parameters:
string subName The first part of the time zones desired.

Throws:
FileException on Posix systems if it fails to read from disk. DateTimeException on Windows systems if it fails to read the registry.

class LocalTime: std.datetime.TimeZone;
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 PosixTimeZone and 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.

static pure nothrow immutable(LocalTime) opCall();
LocalTime is a singleton class. LocalTime returns its only instance.

const nothrow @property string name();
The name of the time zone per the TZ Database. This is the name used to get a TimeZone by name with 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 stdName and 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:
Wikipedia entry on TZ Database
List of Time Zones

const nothrow @property string stdName();
Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST is 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.

const nothrow @property string dstName();
Typically, the abbreviation (generally 3 or 4 letters) for the time zone when DST 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.

const nothrow @property bool hasDST();
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 hasDST because the time zone did at some point have DST.

const nothrow bool dstInEffect(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be checked for DST in this time zone.

const nothrow long utcToTZ(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

See Also:
TimeZone.utcToTZ

const nothrow long tzToUTC(long adjTime);
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:
TimeZone.tzToUTC

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

class UTC: std.datetime.TimeZone;
A TimeZone which represents UTC.

static pure nothrow immutable(UTC) opCall();
UTC is a singleton class. UTC returns its only instance.

const nothrow @property bool hasDST();
Always returns false.

const nothrow bool dstInEffect(long stdTime);
Always returns false.

const nothrow long utcToTZ(long stdTime);
Returns the given hnsecs without changing them at all.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

See Also:
TimeZone.utcToTZ

const nothrow long tzToUTC(long adjTime);
Returns the given hnsecs without changing them at all.

See Also:
TimeZone.tzToUTC

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

const nothrow Duration utcOffsetAt(long stdTime);
Returns a core.time.Duration of 0.

Parameters:
long stdTime The UTC time for which to get the offset from UTC for this time zone.

class SimpleTimeZone: std.datetime.TimeZone;
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 SysTime's fromISOString, fromISOExtString, and fromSimpleString.

name and 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.

const nothrow @property bool hasDST();
Always returns false.

const nothrow bool dstInEffect(long stdTime);
Always returns false.

const nothrow long utcToTZ(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

const nothrow long tzToUTC(long adjTime);
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).

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

const nothrow Duration utcOffsetAt(long stdTime);
Returns utcOffset as a core.time.Duration.

Parameters:
long stdTime The UTC time for which to get the offset from UTC for this time zone.

immutable this(Duration utcOffset, string stdName = "");
immutable this(int utcOffset, string stdName = "");
Parameters:
Duration utcOffset | This time zone's offset from UTC in minutes with west of UTC being negative (it is added to UTC to get the adjusted time).
string stdName | The stdName for this time zone.

const pure nothrow @property @safe int utcOffset();
The number of minutes the offset from UTC is (negative is west of UTC, positive is east).

class PosixTimeZone: std.datetime.TimeZone;
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 PosixTimeZone">PosixTimeZone (which reads its information from the TZ Database files on disk) on Windows by providing the TZ Database files and telling PosixTimeZone.getTimeZone where the directory holding them is.

To get a PosixTimeZone, either call PosixTimeZone.getTimeZone (which allows specifying the location the time zone files) or call TimeZone.getTimeZone (which will give a PosixTimeZone on Posix systems and a 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 PosixTimeZone with a time zone whose name starts with "right/". Those time zone files do include leap seconds, and PosixTimeZone will take them into account (though posix systems which use a "right/" time zone as their local time zone will not take leap seconds into account even though they're in the file).

See Also:
Home of the TZ Database files
Wikipedia entry on TZ Database
List of Time Zones

const nothrow @property bool hasDST();
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 hasDST because the time zone did at some point have DST.

const nothrow bool dstInEffect(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be checked for DST in this time zone.

const nothrow long utcToTZ(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

const nothrow long tzToUTC(long adjTime);
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).

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

string defaultTZDatabaseDir;
The default directory where the TZ Database files are. It's empty for Windows, since Windows doesn't have them.

static immutable(PosixTimeZone) getTimeZone(string name, string tzDatabaseDir = defaultTZDatabaseDir);
Returns a 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:
Wikipedia entry on TZ Database
List of Time Zones

Parameters:
string name | The TZ Database name of the desired time zone
string 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 PosixTimeZones.

Throws:
DateTimeException if the given time zone could not be found or FileException if the TZ Database file could not be opened.

Examples:
auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles");

assert(tz.name == "America/Los_Angeles");
assert(tz.stdName == "PST");
assert(tz.dstName == "PDT");

static string[] getInstalledTZNames(string subName = "", string tzDatabaseDir = defaultTZDatabaseDir);
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".

Parameters:
string subName The first part of the desired time zones.

Throws:
FileException if it fails to read from disk.

class WindowsTimeZone: std.datetime.TimeZone;
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 PosixTimeZone (which reads its information from the TZ Database files on disk) on Windows by providing the TZ Database files and telling 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 PosixTimeZone rather than WindowsTimeZone. However, because 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.

WindowsTimeZone does not exist on Posix systems.

To get a WindowsTimeZone, either call WindowsTimeZone.getTimeZone or call TimeZone.getTimeZone (which will give a PosixTimeZone on Posix systems and a WindowsTimeZone on Windows systems).

See Also:
Home of the TZ Database files

const nothrow @property bool hasDST();
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 hasDST because the time zone did at some point have DST.

const nothrow bool dstInEffect(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be checked for DST in this time zone.

const nothrow long utcToTZ(long stdTime);
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.

Parameters:
long stdTime The UTC time that needs to be adjusted to this time zone's time.

const nothrow long tzToUTC(long adjTime);
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).

Parameters:
long adjTime The time in this time zone that needs to be adjusted to UTC time.

static immutable(WindowsTimeZone) getTimeZone(string name);
Returns a TimeZone with the given name per the Windows time zone names. The time zone information is fetched from the Windows registry.

See Also:
Wikipedia entry on TZ Database
List of Time Zones

Parameters:
string name The TZ Database name of the desired time zone.

Throws:
DateTimeException if the given time zone could not be found.

Examples:
    auto tz = TimeZone.getTimeZone("America/Los_Angeles");

static string[] getInstalledTZNames();
Returns a list of the names of the time zones installed on the system.

void setTZEnvVar(string tzDatabaseName);
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 clearTZEnvVar();
This function is Posix-Only.

Clears the TZ environment variable.

string tzDatabaseNameToWindowsTZName(string tzName);
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.

See Also:
Windows <-> TZ Database Name Conversion Table

Parameters:
string tzName The TZ Database name to convert.

Throws:
DateTimeException if the given tzName cannot be converted.

string windowsTZNameToTZDatabaseName(string tzName);
Converts the given Windows time zone name to a corresponding TZ Database name.

See Also:
Windows <-> TZ Database Name Conversion Table

Parameters:
string tzName The TZ Database name to convert.

Throws:
DateTimeException if the given tzName cannot be converted.

struct StopWatch;
StopWatch measures time as precisely as possible.

This class uses a high-performance counter. On Windows systems, it uses QueryPerformanceCounter, and on Posix systems, it uses clock_gettime if available, and gettimeofday otherwise.

But the precision of 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 StopWatch's accuracy.

Examples:
void foo()
{
    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 know the number of seconds,
    // use properties of TickDuration.
    // (seconds, msecs, usecs, hnsecs)
    foreach(t; times)
       sum += t.hnsecs;
    writeln("Average time: ", sum/n, " hnsecs");
}

this(AutoStart autostart);
Auto start with constructor.

const pure nothrow @safe bool opEquals(const StopWatch rhs);
const pure nothrow @safe bool opEquals(ref const StopWatch rhs);

@safe void reset();
Resets the stop watch.

@safe void start();
Starts the stop watch.

@safe void stop();
Stops the stop watch.

const @safe TickDuration peek();
Peek at the amount of time which has passed since the stop watch was started.

@safe void setMeasured(TickDuration d);
Set the amount of time which has been measured since the stop watch was started.

const pure nothrow @property @safe bool running();
Confirm whether this stopwatch is measuring time.

TickDuration[lengthof!(fun)()] benchmark(fun...)(uint n);
Benchmarks code for speed assessment and comparison.

Parameters:
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 core.time.TickDuration) that it took to call each function n times. The first value is the length of time that it took to call fun[0] n times. The second value is the length of time it took to call fun[1] n times. Etc.

Examples:
int a;
void f0() {}
void f1() {auto b = a;}
void f2() {auto b = to!(string)(a);}
auto r = benchmark!(f0, f1, f2)(10_000);
writefln("Milliseconds to call fun[0] n times: %s", r[0].to!("msecs", int));

struct ComparingBenchmarkResult;
Return value of benchmark with two functions comparing.

const pure nothrow @property @safe real point();
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.

const pure nothrow @property @safe TickDuration baseTime();
The time required of the base function

const pure nothrow @property @safe TickDuration targetTime();
The time required of the target function

ComparingBenchmarkResult comparingBenchmark(alias baseFunc, alias targetFunc, int times = 4095)();
Benchmark with two functions comparing.

Parameters:
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.

Examples:
void f1() {
   // ...
}
void f2() {
   // ...
}

void main() {
   auto b = comparingBenchmark!(f1, f2, 0x80);
   writeln(b.point);
}

template isTimePoint(T)
Whether the given type defines all of the necessary functions for it to function as a time point.

static pure nothrow bool yearIsLeapYear(int year);
Whether the given Gregorian Year is a leap year.

Parameters:
int year The year to to be tested.

pure nothrow long unixTimeToStdTime(time_t unixTime);
Converts a time_t (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).

Parameters:
time_t unixTime The time_t to convert.

pure nothrow time_t stdTimeToUnixTime(long stdTime);
Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch and hnsecs as its units) to time_t (which uses midnight, January 1st, 1970 UTC as its epoch and seconds as its units). If time_t is 32 bits, rather than 64, and the result can't fit in a 32-bit value, then the closest value that can be held in 32 bits will be used (so time_t.max if it goes over and time_t.min if it goes under).

Note:
While Windows systems require that time_t be non-negative (in spite of time_t being signed), this function still returns negative numbers on Windows, since it's more flexible to allow negative time_t for those who need it. If on Windows and using the standard C functions or Win32 API functions which take a time_t, check whether the return value of stdTimeToUnixTime is non-negative.

Parameters:
long stdTime The std time to convert.

SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime());
This function is Windows-Only.

Converts a SYSTEMTIME struct to a SysTime.

Parameters:
SYSTEMTIME* st | The SYSTEMTIME struct to convert.
TimeZone tz | The time zone that the time in the SYSTEMTIME struct is assumed to be (if the SYSTEMTIME was supplied by a Windows system call, the SYSTEMTIME will either be in local time or UTC, depending on the call).

Throws:
DateTimeException if the given SYSTEMTIME will not fit in a SysTime, which is highly unlikely to happen given that SysTime.max is in 29,228 A.D. and the maximum SYSTEMTIME is in 30,827 A.D.

SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime);
This function is Windows-Only.

Converts a SysTime to a SYSTEMTIME struct.

The SYSTEMTIME which is returned will be set using the given SysTime's time zone, so to get the SYSTEMTIME in UTC, set the SysTime's time zone to UTC.

Parameters:
SysTime sysTime The SysTime to convert.

Throws:
DateTimeException if the given SysTime will not fit in a SYSTEMTIME. This will only happen if the SysTime's date is prior to 1601 A.D.

long FILETIMEToStdTime(const FILETIME* ft);
This function is Windows-Only.

Converts a FILETIME struct to the number of hnsecs since midnight, January 1st, 1 A.D.

Parameters:
FILETIME* ft The FILETIME struct to convert.

Throws:
DateTimeException if the given FILETIME cannot be represented as the return value.

SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime());
This function is Windows-Only.

Converts a FILETIME struct to a SysTime.

Parameters:
FILETIME* ft | The FILETIME struct to convert.
TimeZone tz | The time zone that the SysTime will be in (FILETIMEs are in UTC).

Throws:
DateTimeException if the given FILETIME will not fit in a SysTime.

FILETIME stdTimeToFILETIME(long stdTime);
This function is Windows-Only.

Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a FILETIME struct.

Parameters:
sysTime The SysTime to convert.

Throws:
DateTimeException if the given value will not fit in a FILETIME.

FILETIME SysTimeToFILETIME(SysTime sysTime);
This function is Windows-Only.

Converts a SysTime to a FILETIME struct.

FILETIMEs are always in UTC.

Parameters:
SysTime sysTime The SysTime to convert.

Throws:
DateTimeException if the given SysTime will not fit in a FILETIME.

alias uint DosFileTime;
Type representing the DOS file date/time format.

SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime());
Converts from DOS file date/time to SysTime.

Parameters:
DosFileTime dft | The DOS file time to convert.
TimeZone tz | The time zone which the DOS file time is assumed to be in.

Throws:
DateTimeException if the DosFileTime is invalid.

DosFileTime SysTimeToDosFileTime(SysTime sysTime);
Converts from SysTime to DOS file date/time.

Parameters:
SysTime sysTime The SysTime to convert.

Throws:
DateTimeException if the given SysTime cannot be converted to a DosFileTime.

bool validTimeUnits(string[] units...);
Whether all of the given strings are valid units of time.

"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.

int cmpTimeUnits(string lhs, string rhs);
Compares two time unit strings. "years" are the largest units and "hnsecs" are the smallest.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

Throws:
DateTimeException if either of the given strings is not a valid time unit string.

template CmpTimeUnits(string lhs, string rhs) if (validTimeUnits(lhs, rhs))
Compares two time unit strings at compile time. "years" are the largest units and "hnsecs" are the smallest.

This template is used instead of cmpTimeUnits because exceptions can't be thrown at compile time and cmpTimeUnits must enforce that the strings it's given are valid time unit strings. This template uses a template constraint instead.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

pure nothrow bool valid(string units)(int value);
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).

Parameters:
units | The units of time to validate.
value | The number to validate.

Examples:
assert(valid!"hours"(12));
assert(!valid!"hours"(32));
assert(valid!"months"(12));
assert(!valid!"months"(13));

pure nothrow bool valid(string units)(int year, int month, int day);
Returns whether the given day is valid for the given year and month.

Parameters:
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.

pure void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__);
Parameters:
units | The units of time to validate.
value | The number to validate.
file | The file that the DateTimeException will list if thrown.
line | The line number that the DateTimeException will list if thrown.

Throws:
DateTimeException if valid!units(value) is false.

pure void enforceValid(string units)(int year, Month month, int day, string file = __FILE__, size_t line = __LINE__);
Parameters:
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 DateTimeException will list if thrown.
line | The line number that the DateTimeException will list if thrown.

Throws:
DateTimeException if valid!"days"(year, month, day) is false.

static pure int monthsToMonth(int currMonth, int month);
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.

Parameters:
int currMonth | The current month of the year.
int month | The month of the year to get the number of months to.

static pure nothrow int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow);
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.

Parameters:
DayOfWeek currDoW | The current day of the week.
DayOfWeek dow | The day of the week to get the number of days to.

auto measureTime(alias func)();
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, func will run. func is a unary function that takes a core.time.TickDuration.

Examples:
writeln("benchmark start!");
{
auto mt = measureTime!((a){assert(a.seconds);});
doSomething();
}
writeln("benchmark end!");

Copyright 2010 - 2011 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.encoding

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), and WINDOWS-1252.

  • The type AsciiChar represents an ASCII character.
  • The type AsciiString represents an ASCII string.
  • The type Latin1Char represents an ISO-8859-1 character.
  • The type Latin1String represents an ISO-8859-1 string.
  • The type Windows1252Char represents a Windows-1252 character.
  • The type 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 EncodingScheme and its subclasses. To construct a run-time encoder/decoder, one does e.g.

    auto e = EncodingScheme.create("utf-8");

This library supplies EncodingScheme subclasses for ASCII, ISO-8859-1 (also known as LATIN-1), 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 EncodingScheme subclasses for any other encoding.

License:
Boost License 1.0.

Authors:
Janice Caron

Source:
std/encoding.d

dchar INVALID_SEQUENCE;
Special value returned by safeDecode

enum AsciiChar;
alias immutable(AsciiChar)[] AsciiString;
Defines various character sets.

enum Latin1Char;
Defines an Latin1-encoded character.

alias immutable(Latin1Char)[] Latin1String;
Defines an Latin1-encoded string (as an array of immutable(Latin1Char)).

enum Windows1252Char;
Defines a Windows1252-encoded character.

alias immutable(Windows1252Char)[] Windows1252String;
Defines an Windows1252-encoded string (as an array of immutable(Windows1252Char)).

bool isValidCodePoint(dchar c);
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).

Supercedes:
This function supercedes std.utf.startsValidDchar().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
dchar c the code point to be tested

string encodingName(T)();
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, WINDOWS-1252

Examples:
 assert(encodingName!(Latin1Char) == "ISO-8859-1");

bool canEncode(E)(dchar c);
Returns true iff it is possible to represent the specifed 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, WINDOWS-1252

Examples:
 assert(canEncode!(Latin1Char)('A'));

bool isValidCodeUnit(E)(E c);
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, WINDOWS-1252

Parameters:
c the code unit to be tested

bool isValid(E)(const(E)[] s);
Returns true if the string is encoded correctly

Supercedes:
This function supercedes std.utf.validate(), however note that this function returns a bool indicating whether the input was valid or not, wheras the older funtion would throw an exception.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be tested

size_t validLength(E)(const(E)[] s);
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, WINDOWS-1252

Parameters:
s the string to be tested

immutable(E)[] sanitize(E)(immutable(E)[] s);
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, WINDOWS-1252

Parameters:
s the string to be sanitized

size_t firstSequence(E)(const(E)[] s);
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, WINDOWS-1252

Parameters:
s the string to be sliced

size_t lastSequence(E)(const(E)[] s);
Returns the length 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, WINDOWS-1252

Parameters:
s the string to be sliced

ptrdiff_t index(E)(const(E)[] s, int 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.

Supercedes:
This function supercedes std.utf.toUTFindex().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be counted

dchar decode(S)(ref S s);
Decodes a single code point.

This function removes one or more code units from the start of a string, and returns the decoded code point which those code units represent.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Supercedes:
This function supercedes std.utf.decode(), however, note that the function codePoints() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

dchar decodeReverse(E)(ref const(E)[] s);
Decodes a single code point from the end of a string.

This function removes one or more code units from the end of a string, and returns the decoded code point which those code units represent.

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, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

dchar safeDecode(S)(ref S s);
Decodes a single code point. The input does not have to be valid.

This function removes one or more code units from the start of a string, and returns the decoded code point which those code units represent.

This function will accept an invalidly encoded string 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.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

size_t encodedLength(E)(dchar c);
Returns the number of code units required to encode a single 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 as a template parameter.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

E[] encode(E)(dchar c);
Encodes a single code point.

This function encodes a single code point into one or more code units. It returns a string containing those code units.

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.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

size_t encode(E)(dchar c, E[] array);
Encodes a single code point into an array.

This function encodes a single code point into one or more code units The code units are stored in a user-supplied fixed-size array, which must be passed by reference.

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.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

Returns:
the number of code units written to the array

void encode(E)(dchar c, void delegate(E) dg);
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.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

CodePoints!(E) codePoints(E)(immutable(E)[] s);
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.

Supercedes:
This function supercedes std.utf.decode().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be decoded

Examples:
 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.

CodeUnits!(E) codeUnits(E)(dchar c);
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.

Supercedes:
This function supercedes std.utf.encode().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
d the code point to be encoded

Examples:
 dchar d = '\u20AC';
 foreach(c;codeUnits!(char)(d))
 {
     writefln("%X",c)
 }
 // will print
 // E2
 // 82
 // AC

size_t encode(Tgt, Src, R)(in Src[] s, R range);
Encodes c in units of type E and writes the result to the output range R. Returns the number of Es written.

void transcode(Src, Dst)(immutable(Src)[] s, out immutable(Dst)[] r);
Convert a string from one encoding to another. (See also to!() below).

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Supercedes:
This function supercedes std.utf.toUTF8(), std.utf.toUTF16() and std.utf.toUTF32() (but note that to!() supercedes it more conveniently).

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s | the source string
r | the destination string

Examples:
 wstring ws;
 transcode("hello world",ws);
     // transcode from UTF-8 to UTF-16

 Latin1String ls;
 transcode(ws, ls);
     // transcode from UTF-16 to ISO-8859-1

class EncodingException: object.Exception;
The base class for exceptions thrown by this module

abstract class EncodingScheme;
Abstract base class of all encoding schemes

static void register(string className);
Registers a subclass of EncodingScheme.

This function allows user-defined subclasses of EncodingScheme to be declared in other modules.

Examples:
 class Amiga1251 : EncodingScheme
 {
     shared static this()
     {
         EncodingScheme.register("path.to.Amiga1251");
     }
 }

static EncodingScheme create(string encodingName);
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.

Examples:
 auto scheme = EncodingScheme.create("Amiga-1251");

abstract const const string toString();
Returns the standard name of the encoding scheme

abstract const const string[] names();
Returns an array of all known names for this encoding scheme

abstract const const bool canEncode(dchar c);
Returns true if the character c can be represented in this encoding scheme.

abstract const const size_t encodedLength(dchar c);
Returns the number of ubytes required to encode this code point.

The input to this function MUST be a valid code point.

Parameters:
dchar c the code point to be encoded

Returns:
the number of ubytes required.

abstract const const size_t encode(dchar c, ubyte[] buffer);
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.

Parameters:
dchar c the code point to be encoded

Returns:
the number of ubytes written.

abstract const const dchar decode(ref const(ubyte)[] s);
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.

Parameters:
const(ubyte)[] s the array whose first code point is to be decoded

abstract const const dchar safeDecode(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.

Parameters:
const(ubyte)[] s the array whose first code point is to be decoded

abstract const const @property immutable(ubyte)[] replacementSequence();
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 '?'.

bool isValid(const(ubyte)[] s);
Returns true if the array is encoded correctly

Parameters:
const(ubyte)[] s the array to be tested

size_t validLength(const(ubyte)[] s);
Returns the length of the longest possible substring, starting from the first element, which is validly encoded.

Parameters:
const(ubyte)[] s the array to be tested

immutable(ubyte)[] sanitize(immutable(ubyte)[] s);
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.

Parameters:
immutable(ubyte)[] s the string to be sanitized

size_t firstSequence(const(ubyte)[] s);
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.

Parameters:
const(ubyte)[] s the array to be sliced

size_t count(const(ubyte)[] s);
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.

Parameters:
const(ubyte)[] s the string to be counted

ptrdiff_t index(const(ubyte)[] s, size_t 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.

Parameters:
const(ubyte)[] s the string to be counted

class EncodingSchemeASCII: std.encoding.EncodingScheme;
EncodingScheme to handle ASCII

This scheme recognises the following names: "ANSI_X3.4-1968", "ANSI_X3.4-1986", "ASCII", "IBM367", "ISO646-US", "ISO_646.irv:1991", "US-ASCII", "cp367", "csASCII" "iso-ir-6", "us"

class EncodingSchemeLatin1: std.encoding.EncodingScheme;
EncodingScheme to handle Latin-1

This scheme recognises the following names: "CP819", "IBM819", "ISO-8859-1", "ISO_8859-1", "ISO_8859-1:1987", "csISOLatin1", "iso-ir-100", "l1", "latin1"

class EncodingSchemeWindows1252: std.encoding.EncodingScheme;
EncodingScheme to handle Windows-1252

This scheme recognises the following names: "windows-1252"

class EncodingSchemeUtf8: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-8

This scheme recognises the following names: "UTF-8"

class EncodingSchemeUtf16Native: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-16 in native byte order

This scheme recognises the following names: "UTF-16LE" (little-endian architecture only) "UTF-16BE" (big-endian architecture only)

class EncodingSchemeUtf32Native: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-32 in native byte order

This scheme recognises the following names: "UTF-32LE" (little-endian architecture only) "UTF-32BE" (big-endian architecture only)

Copyright Janice Caron 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.exception

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 = enforceEx!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);
}

License:
Boost License 1.0

Authors:
Andrei Alexandrescu and Jonathan M Davis

Source:
std/exception.d

void assertNotThrown(T : Throwable = Exception, E)(lazy E expression, string msg = null, string file = __FILE__, size_t line = __LINE__);
Asserts that the given expression does not throw the given type of Throwable. If a Throwable of the given type is thrown, it is caught and does not escape assertNotThrown. Rather, an AssertError is thrown. However, any other Throwables will escape.

Parameters:
T | The Throwable to test for.
expression | The expression to test.
msg | Optional message to output on test failure.

Throws:
AssertError if the given Throwable is thrown.

Examples:
assertNotThrown!StringException(enforceEx!StringException(true, "Error!"));

//Exception is the default.
assertNotThrown(enforceEx!StringException(true, "Error!"));

assert(collectExceptionMsg!AssertError(assertNotThrown!StringException(
           enforceEx!StringException(false, "Error!"))) ==
       `assertNotThrown failed: StringException was thrown.`);

void assertThrown(T : Throwable = Exception, E)(lazy E expression, string msg = null, string file = __FILE__, size_t line = __LINE__);
Asserts that the given expression throws the given type of Throwable. The Throwable is caught and does not escape assertThrown. However, any other Throwables will escape, and if no Throwable of the given type is thrown, then an AssertError is thrown.

Parameters:
T | The Throwable to test for.
expression | The expression to test.
msg | Optional message to output on test failure.

Throws:
AssertError if the given Throwable is not thrown.

Examples:
assertThrown!StringException(enforceEx!StringException(false, "Error!"));

//Exception is the default.
assertThrown(enforceEx!StringException(false, "Error!"));

assert(collectExceptionMsg!AssertError(assertThrown!StringException(
           enforceEx!StringException(true, "Error!"))) ==
       `assertThrown failed: No StringException was thrown.`);

T enforce(T)(T value, lazy const(char)[] msg = null, string file = __FILE__, size_t line = __LINE__);
If !!value is true, value is returned. Otherwise, new Exception(msg) is thrown.

Note:
enforce is used to throw exceptions and is therefore intended to aid in error handling. It is not intended for verifying the logic of your program. That is what assert is for. Also, do not use enforce inside of contracts (i.e. inside of in and out blocks and invariants), because they will be compiled out when compiling with -release. Use assert in contracts.

Example:
auto f = enforce(fopen("data.txt"));
auto line = readln(f);
enforce(line.length, "Expected a non-empty line.");

T enforce(T, string file, size_t line = __LINE__)(T value, lazy const(char)[] msg = null);
Scheduled for deprecation in January 2013. If passing the file or line number explicitly, please use the version of enforce which takes them as function arguments. Taking them as template arguments causes unnecessary template bloat.

T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)(T value, scope Dg dg);
If !!value is true, value is returned. Otherwise, the given delegate is called.

The whole safety and purity are inferred from Dg's safety and purity.

T enforce(T)(T value, lazy Throwable ex);
If !!value is true, value is returned. Otherwise, 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 errnoEnforce(T, string file = __FILE__, size_t line = __LINE__)(T value, lazy string msg = null);
If !!value is true, value is returned. Otherwise, new ErrnoException(msg) is thrown. ErrnoException assumes that the last operation set errno to an error code.

Example:
auto f = errnoEnforce(fopen("data.txt"));
auto line = readln(f);
enforce(line.length); // expect a non-empty line

template enforceEx(E) if (is(typeof(new E("", "std\\exception.d", 538))))
If !!value is true, value is returned. Otherwise, new E(msg, file, line) is thrown. Or if E doesn't take a message and can be constructed with new E(file, line), then new E(file, line) will be thrown.

Example:
 auto f = enforceEx!FileMissingException(fopen("data.txt"));
 auto line = readln(f);
 enforceEx!DataCorruptionException(line.length);

template enforceEx(E) if (is(typeof(new E(""))) && !is(typeof(new E("", "std\\exception.d", 566))) && !is(typeof(new E("std\\exception.d", 566))))
Deprecated. It will be removed in October 2012. Please use the version of enforceEx which takes an exception that constructs with new E(msg, file, line).

If !!value is true, value is returned. Otherwise, new E(msg) is thrown.

T collectException(T = Exception, E)(lazy E expression, ref E result);
Catches and returns the exception thrown from the given expression. If no exception is thrown, then null is returned and result is set to the result of the expression.

Note that while collectException can be used to collect any Throwable and not just Exceptions, it is generally ill-advised to catch anything that is neither an Exception nor a type derived from Exception. So, do not use collectException to collect non-Exceptions unless you're sure that that's what you really want to do.

Parameters:
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.

Example:
int[] a = new int[3];
int b;
assert(collectException(a[4], b));

T collectException(T : Throwable = Exception, E)(lazy E expression);
Catches and returns the exception thrown from the given expression. If no exception is thrown, then null is returned. E can be void.

Note that while collectException can be used to collect any Throwable and not just Exceptions, it is generally ill-advised to catch anything that is neither an Exception nor a type derived from Exception. So, do not use collectException to collect non-Exceptions unless you're sure that that's what you really want to do.

Parameters:
T | The type of exception to catch.
expression | The expression which may throw an exception.

string collectExceptionMsg(T = Exception, E)(lazy E expression);
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. E can be void.

If an exception is thrown but it has an empty message, then emptyExceptionMsg is returned.

Note that while collectExceptionMsg can be used to collect any Throwable and not just Exceptions, it is generally ill-advised to catch anything that is neither an Exception nor a type derived from Exception. So, do not use collectExceptionMsg to collect non-Exceptions unless you're sure that that's what you really want to do.

Parameters:
T | The type of exception to catch.
expression | The expression which may throw an exception.

Examples:
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);

string emptyExceptionMsg;
Value that collectExceptionMsg returns when it catches an exception with an empty exception message.

pure nothrow immutable(T)[] assumeUnique(T)(T[] array);
pure nothrow immutable(T)[] assumeUnique(T)(ref T[] array);
Casts a mutable array to an immutable array in an idiomatic manner. Technically, assumeUnique just inserts a cast, but its name documents assumptions on the part of the caller. assumeUnique(arr) should only be called when there are no more active mutable aliases to elements of arr. To strenghten this assumption, assumeUnique(arr) also clears arr before returning. Essentially assumeUnique(arr) indicates commitment from the caller that there is no more mutable access to any of arr's elements (transitively), and that all future accesses will be done through the immutable array returned by assumeUnique.

Typically, assumeUnique is used to return arrays from functions that have allocated and built them.

Example:
 string letters()
 {
   char[] result = new char['z' - 'a' + 1];
   foreach (i, ref e; result)
   {
     e = 'a' + i;
   }
   return assumeUnique(result);
 }

The use in the example above is correct because result was private to letters and is unaccessible in writing after the function returns. The following example shows an incorrect use of 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 = '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 buffer, replace the last line with:
 return to!(string)(sneaky); // not that sneaky anymore

The call will duplicate the array appropriately.

Checking for uniqueness during compilation is possible in certain cases (see the unique and lent keywords in the ArchJava language), but complicates the language considerably. The downside of 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 assumeUnique is simple and rare enough to be tolerable.

pure nothrow @trusted bool pointsTo(S, T, Tdummy = void)(auto ref const S source, auto ref const T target);
Returns true if source's representation embeds a pointer that points to target's representation or somewhere inside it.

Note that evaluating pointsTo(x, x) checks whether 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).

class ErrnoException: object.Exception;
Thrown if errors that set errno occur.

Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.file

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 std.stdio.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Jonathan M Davis

Source:
std/file.d

class FileException: object.Exception;
Exception thrown for file I/O errors.

immutable uint errno;
OS error code.

this(in char[] name, in char[] msg, string file = __FILE__, size_t line = __LINE__);
Constructor which takes an error message.

Parameters:
char[] name | Name of file for which the error occurred.
char[] msg | Message describing the error.
string file | The file where the error occurred.
size_t line | The line where the error occurred.

this(in char[] name, uint errno = .GetLastError(), string file = __FILE__, size_t line = __LINE__);
Constructor which takes the error number (GetLastError in Windows, errno in Posix).

Parameters:
char[] name | Name of file for which the error occurred.
msg | Message describing the error.
string file | The file where the error occurred.
size_t line | The line where the error occurred.

void[] read(in char[] name, size_t upTo = (uint).max);
Read entire contents of file name and returns it as an untyped array. If the file size is larger than upTo, only upTo bytes are read.

Example:
import std.file, std.stdio;
void main()
{
   auto bytes = cast(ubyte[]) read("filename", 5);
   if (bytes.length == 5)
       writefln("The fifth byte of the file is 0x%x", bytes[4]);
}

Returns:
Untyped array of bytes read.

Throws:
FileException on error.

S readText(S = string)(in char[] name);
Read and validates (using std.utf.validate) a text file. 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 name is different from the width of elements of S, validation will fail.

Returns:
Array of characters read.

Throws:
FileException on file error, UTFException on UTF decoding error.

Example:
enforce(system("echo abc>deleteme") == 0);
scope(exit) remove("deleteme");
enforce(chomp(readText("deleteme")) == "abc");

void write(in char[] name, const void[] buffer);
Write buffer to file name.

Throws:
FileException on error.

Example:
import std.file;
void main()
{
   int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
   write("filename", a);
   assert(cast(int[]) read("filename") == a);
}

void append(in char[] name, in void[] buffer);
Appends buffer to file name.

Throws:
FileException on error.

Example:
import std.file;
void main()
{
   int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
   write("filename", a);
   int[] b = [ 13, 21 ];
   append("filename", b);
   assert(cast(int[]) read("filename") == a ~ b);
}

void rename(in char[] from, in char[] to);
Rename file from to to.

Throws:
FileException on error.

void remove(in char[] name);
Delete file name.

Throws:
FileException on error.

ulong getSize(in char[] name);
Get size of file name in bytes.

Throws:
FileException on error (e.g., file not found).

void getTimes(in char[] name, out SysTime fileAccessTime, out SysTime fileModificationTime);
Get the access and modified times of file name.

Parameters:
char[] name | File name to get times for.
SysTime fileAccessTime | Time the file was last accessed.
SysTime fileModificationTime | Time the file was last modified.

Throws:
FileException on error.

void getTimesWin(in char[] name, out SysTime fileCreationTime, out SysTime fileAccessTime, out SysTime fileModificationTime);
This function is Windows-Only.

Get creation/access/modified times of file name.

This is the same as getTimes except that it also gives you the file creation time - which isn't possible on Posix systems.

Parameters:
char[] name | File name to get times for.
SysTime fileCreationTime | Time the file was created.
SysTime fileAccessTime | Time the file was last accessed.
SysTime fileModificationTime | Time the file was last modified.

Throws:
FileException on error.

SysTime timeLastModified(in char[] name);
Returns the time that the given file was last modified.

Throws:
FileException if the given file does not exist.

SysTime timeLastModified(in char[] name, SysTime returnIfMissing);
Returns the time that the given file was last modified. If the file does not exist, returns returnIfMissing.

A frequent usage pattern occurs in build automation tools such as make or ant. To check whether file target must be rebuilt from file source (i.e., target is older than source or does not exist), use the comparison below. The code throws a FileException if source does not exist (as it should). On the other hand, the SysTime.min default makes a non-existing target seem infinitely old so the test correctly prompts building it.

Parameters:
char[] name | The name of the file to get the modification time for.
SysTime returnIfMissing | The time to return if the given file does not exist.

Examples:
if(timeLastModified(source) >= timeLastModified(target, SysTime.min))
{
    // must (re)build
}
else
{
    // target is up-to-date
}

@property bool exists(in char[] name);
Returns whether the given file (or directory) exists.

uint getAttributes(in char[] name);
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 GetFileAttributes, whereas on Posix systems, they're the st_mode value which is part of the stat struct gotten by calling the 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.

Parameters:
char[] name The file to get the attributes of.

uint getLinkAttributes(in char[] name);
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 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.

Parameters:
char[] name The file to get the symbolic link attributes of.

Throws:
FileException on error.

@property bool isDir(in char[] name);
Returns whether the given file is a directory.

Parameters:
char[] name The path to the file.

Throws:
FileException if the given file does not exist.

Examples:
assert(!"/etc/fonts/fonts.conf".isDir);
assert("/usr/share/include".isDir);

nothrow bool attrIsDir(uint attributes);
Returns whether the given file attributes are for a directory.

Parameters:
uint attributes The file attributes.

Examples:
assert(!attrIsDir(getAttributes("/etc/fonts/fonts.conf")));
assert(!attrIsDir(getLinkAttributes("/etc/fonts/fonts.conf")));

@property bool isFile(in char[] name);
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 isFile or isDir will return true for any given file.

On Posix systems, if isFile is 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 isFile and isDir to be false for a particular file (in which case, it's a special file). You can use getAttributes to get the attributes to figure out what type of special it is, or you can use dirEntry to get at its statBuf, which is the result from stat. In either case, see the man page for stat for more information.

Parameters:
char[] name The path to the file.

Throws:
FileException if the given file does not exist.

Examples:
assert("/etc/fonts/fonts.conf".isFile);
assert(!"/usr/share/include".isFile);

nothrow bool attrIsFile(uint attributes);
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 attrIsFile or attrIsDir will return true for the attributes of any given file.

On Posix systems, if attrIsFile is 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 attrIsFile and attrIsDir to be 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 stat for more information).

Parameters:
uint attributes The file attributes.

Examples:
assert(attrIsFile(getAttributes("/etc/fonts/fonts.conf")));
assert(attrIsFile(getLinkAttributes("/etc/fonts/fonts.conf")));

bool isSymlink(C)(const(C)[] name);
Returns whether the given file is a symbolic link.

On Windows, returns true when the file is either a symbolic link or a junction point.

Parameters:
name The path to the file.

Throws:
FileException if the given file does not exist.

nothrow bool attrIsSymlink(uint attributes);
Returns whether the given file attributes are for a symbolic link.

On Windows, return true when the file is either a symbolic link or a junction point.

Parameters:
uint attributes The file attributes.

Examples:
core.sys.posix.unistd.symlink("/etc/fonts/fonts.conf", "/tmp/alink");

assert(!getAttributes("/tmp/alink").isSymlink);
assert(getLinkAttributes("/tmp/alink").isSymlink);

void chdir(in char[] pathname);
Change directory to pathname.

Throws:
FileException on error.

void mkdir(in char[] pathname);
Make directory pathname.

Throws:
FileException on error.

void mkdirRecurse(in char[] pathname);
Make directory and all parent directories as needed.

void rmdir(in char[] pathname);
Remove directory pathname.

Throws:
FileException on error.

void symlink(C1, C2)(const(C1)[] original, const(C2)[] link);
This function is Posix-Only.

Creates a symlink.

Parameters:
original | The file to link from.
link | The symlink to create.

Note:
Relative paths are relative to the current working directory, not the files being linked to or from.

Throws:
FileException on error (which includes if the symlink already exists).

string readLink(C)(const(C)[] link);
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:
FileException on error.

string getcwd();
Get current directory.

Throws:
FileException on error.

struct DirEntry;
Info on a file, similar to what you'd get from stat on a Posix system.

A DirEntry is obtained by using the functions dirEntry (to get the DirEntry for a specific file) or dirEntries (to get a DirEntry for each file/directory in a particular directory).

const @property string name();
Returns the path to the file represented by this DirEntry.

Examples:
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 bool isDir();
Returns whether the file represented by this DirEntry is a directory.

Examples:
auto de1 = dirEntry("/etc/fonts/fonts.conf");
assert(!de1.isDir);

auto de2 = dirEntry("/usr/share/include");
assert(de2.isDir);

@property bool isFile();
Returns whether the file represented by this DirEntry is a file.

On Windows, if a file is not a directory, then it's a file. So, either isFile or isDir will return true.

On Posix systems, if isFile is 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 isFile and isDir to be false for a particular file (in which case, it's a special file). You can use attributes or statBuf to get more information about a special file (see the stat man page for more details).

Examples:
auto de1 = dirEntry("/etc/fonts/fonts.conf");
assert(de1.isFile);

auto de2 = dirEntry("/usr/share/include");
assert(!de2.isFile);

@property bool isSymlink();
Returns whether the file represented by this DirEntry is a symbolic link.

On Windows, return true when the file is either a symbolic link or a junction point.

@property ulong size();
Returns the size of the the file represented by this DirEntry in bytes.

const @property SysTime timeCreated();
This function is Windows-Only.

Returns the creation time of the file represented by this DirEntry.

@property SysTime timeLastAccessed();
Returns the time that the file represented by this 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 timeLastAccessed will return the same value as timeLastModified.

@property SysTime timeLastModified();
Returns the time that the file represented by this DirEntry was last modified.

@property uint attributes();
Returns the attributes of the file represented by this DirEntry.

Note that the file attributes on Windows and Posix systems are completely different. On, Windows, they're what is returned by GetFileAttributes GetFileAttributes Whereas, an Posix systems, they're the st_mode value which is part of the stat struct gotten by calling stat.

On Posix systems, if the file represented by this DirEntry is a symbolic link, then attributes are the attributes of the file pointed to by the symbolic link.

@property uint linkAttributes();
On Posix systems, if the file represented by this DirEntry is a symbolic link, then linkAttributes are the attributes of the symbolic link itself. Otherwise, linkAttributes is identical to attributes.

On Windows, linkAttributes is identical to attributes. It exists on Windows so that you don't have to special-case code for Windows when dealing with symbolic links.

@property stat_t statBuf();
This function is Posix-Only.

The stat struct gotten from calling stat.

deprecated alias listDir(C)(in C[] pathname) listdir;
Deprecated. It will be removed in November 2012. Please use dirEntries instead.

For each file and directory DirEntry in pathname[] pass it to the callback delegate.

Parameters:
callback Delegate that processes each DirEntry in turn. Returns true to continue, false to stop.

Example:
This program lists all the files in its path argument and all subdirectories thereof.
 import std.stdio;
 import std.file;

 void main(string[] args)
 {
    bool callback(DirEntry* de)
    {
      if(de.isDir)
        listdir(de.name, &callback);
      else
        writefln(de.name);

      return true;
    }

    listdir(args[1], &callback);
 }

void copy(in char[] from, in char[] to);
Copy file from to file to. File timestamps are preserved.

void setTimes(in char[] name, SysTime fileAccessTime, SysTime fileModificationTime);
Set access/modified times of file name.

Parameters:
SysTime fileAccessTime | Time the file was last accessed.
SysTime fileModificationTime | Time the file was last modified.

Throws:
FileException on error.

void rmdirRecurse(in char[] pathname);
Remove directory and all of its content and subdirectories, recursively.

Throws:
FileException if there is an error (including if the given file is not a directory).

void rmdirRecurse(ref DirEntry de);
Remove directory and all of its content and subdirectories, recursively.

Throws:
FileException if there is an error (including if the given file is not a directory).

enum SpanMode;
Dictates directory spanning policy for dirEntries (see below).

shallow
Only spans one directory.

depth
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.

breadth
Spans the directory breadth-first, i.e. the content of any subdirectory is spanned right after that subdirectory itself.

auto dirEntries(string path, SpanMode mode, bool followSymlink = true);
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 string if only the name is needed, or 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.

Parameters:
string path | The directory to iterate over.
SpanMode mode | Whether the directory's sub-directories should be iterated over depth-first (depth), breadth-first (breadth), or not at all (shallow).
bool followSymlink | Whether symbolic links which point to directories should be treated as directories and their contents iterated over.

Examples:
// Iterate a directory in depth
foreach (string name; dirEntries("destroy/me", SpanMode.depth))
{
 remove(name);
}
// Iterate a 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 = filter!`endsWith(a.name,".d")`(dirEntries(".",SpanMode.depth));
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, string pattern, SpanMode mode, bool followSymlink = true);
Convenience wrapper for filtering file names with a glob pattern.

Parameters:
string path | The directory to iterate over.
string pattern | String with wildcards, such as "*.d". The supported wildcard strings are described under std.path.globMatch.
SpanMode mode | Whether the directory's sub-directories should be iterated over depth-first (depth), breadth-first (breadth), or not at all (shallow).
bool followSymlink | Whether symbolic links which point to directories should be treated as directories and their contents iterated over.

Examples:
// 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);
//

DirEntry dirEntry(in char[] name);
Returns a DirEntry for the given file (or directory).

Parameters:
char[] name The file (or directory) to get a DirEntry for.

Throws:
FileException if the file does not exist.

Select!(Types.length == 1, Types[0][], Tuple!(Types)[]) slurp(Types...)(string filename, in char[] format);
Reads an entire file into an array.

Example:
// Load file; each line is an int followed by comma, whitespace and a
// double.
auto a = slurp!(int, double)("filename", "%s, %s");

string tempDir();
Returns the path to a directory for temporary files.

On Windows, this function returns the result of calling the Windows API function GetTempPath.

On POSIX platforms, it searches through the following list of directories and returns the first one which is found to exist:
  1. The directory given by the TMPDIR environment variable.
  2. The directory given by the TEMP environment variable.
  3. The directory given by the TMP environment variable.
  4. /tmp
  5. /var/tmp
  6. /usr/tmp

On all platforms, tempDir returns "." 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 tempDir algorithm is inspired by Python's tempfile.tempdir.

string[] listDir(C)(in C[] pathname);
Deprecated. It will be removed in November 2012. Please use dirEntries instead.

Returns the contents of the given directory.

The names in the contents do not include the pathname.

Throws:
FileException on error.

Examples:
This program lists all the files and subdirectories in its path argument.
import std.stdio;
import std.file;

void main(string[] args)
{
    auto dirs = std.file.listDir(args[1]);

    foreach(d; dirs)
        writefln(d);
}

string[] listDir(C, U)(in C[] pathname, U filter, bool followSymlink = true);
Deprecated. It will be removed in November 2012. Please use dirEntries instead.

Returns all the files in the directory and its sub-directories which match pattern or regular expression r.

Parameters:
pathname | The path of the directory to search.
pattern | String with wildcards, such as "*.d". The supported wildcard strings are described under fnmatch() in std.path.
r | Regular expression, for more powerful pattern matching.
followSymlink | Whether symbolic links which point to directories should be treated as directories and their contents iterated over. Ignored on Windows.

Examples:
This program lists all the files with a "d" extension in the path passed as the first argument.
import std.stdio;
import std.file;

void main(string[] args)
{
  auto d_source_files = std.file.listDir(args[1], "*.d");

  foreach(d; d_source_files)
      writefln(d);
}

A regular expression version that searches for all files with "d" or "obj" extensions:
import std.stdio;
import std.file;
import std.regexp;

void main(string[] args)
{
  auto d_source_files = std.file.listDir(args[1], RegExp(r"\.(d|obj)$"));

  foreach(d; d_source_files)
      writefln(d);
}

void listDir(C, U)(in C[] pathname, U callback);
Deprecated. It will be removed in November 2012. Please use dirEntries instead.

For each file and directory name in pathname[], pass it to the callback delegate.

Parameters:
callback Delegate that processes each filename in turn. Returns true to continue, false to stop.

Example:
This program lists all the files in its path argument, including the path.
 import std.stdio;
 import std.path;
 import std.file;

 void main(string[] args)
 {
    auto pathname = args[1];
    string[] result;

    bool listing(string filename)
    {
      result ~= buildPath(pathname, filename);
      return true; // continue
    }

    listdir(pathname, &listing);

    foreach (name; result)
      writefln("%s", name);
 }

Copyright Digital Mars 2007 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.format

This module implements the formatting functionality for strings and I/O. It's comparable to C99's vsprintf() and uses a similar format encoding scheme.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, and Kenji Hara

Source:
std/format.d

class FormatException: object.Exception;
Signals a mismatch between a format and its corresponding argument.

deprecated alias FormatException FormatError;
Deprecated. It will be removed In January 2013. Please use FormatException instead.

uint formattedWrite(Writer, Char, A...)(Writer w, in Char[] fmt, A args);
Interprets variadic argument list args, formats them according to fmt, and sends the resulting characters to w. The encoding of the output is the same as Char. The type Writer must satisfy std.range.isOutputRange!(Writer, Char).

The variadic arguments are normally consumed in order. POSIX-style 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 w. As many arguments as specified in the format string are consumed and formatted. If there are fewer arguments than format specifiers, a 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 %( and %). Each matching pair of %( and %) 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 %| 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.)

Parameters:
w | Output is sent to this writer. Typical output writers include std.array.Appender!string and std.stdio.LockingTextWriter.
fmt | Format string.
args | Variadic argument list.

Returns:
Formatted number of arguments.

Throws:
Mismatched arguments and formats result in a FormatException being thrown.

Format String:
Format strings consist of characters interspersed with 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:

FormatString:
    FormatStringItem*
FormatStringItem:
    '%%'
    '%' Position Flags Width Precision FormatChar
    '%(' FormatString '%)'
    OtherCharacterExceptPercent
Position:
    empty
    Integer '$'
Flags:
    empty
    '-' Flags
    '+' Flags
    '#' Flags
    '0' Flags
    ' ' Flags
Width:
    empty
    Integer
    '*'
Precision:
    empty
    '.'
    '.' Integer
    '.*'
Integer:
    Digit
    Digit Integer
Digit:
    '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
FormatChar:
    's'|'b'|'d'|'o'|'x'|'X'|'e'|'E'|'f'|'F'|'g'|'G'|'a'|'A'

Flags affect formatting depending on the specifier as follows.
Flag Types affected Semantics
'-' numeric Left justify the result in the field. It overrides any 0 flag.
'+' numeric Prefix positive numbers in a signed conversion with a +. It overrides any space flag.
'#' integral ('o') Add to precision as necessary so that the first digit of the octal formatting is a '0', even if both the argument and the Precision are zero.
'#' integral ('x', 'X') If non-zero, prefix result with 0x (0X).
'#' floating Always insert the decimal point and print trailing zeros.
'#' numeric ('0') Use leading zeros to pad rather than spaces (except for the floating point values nan and infinity). Ignore if there's a Precision.
' ' numeric
Prefix positive numbers in a signed conversion with a space.

Width
Specifies the minimum field width. If the width is a *, the next argument, which must be of type int, is taken as the width. If the width is negative, it is as if the - was given as a Flags character.

Precision
Gives the precision for numeric conversions. If the precision is a *, the next argument, which must be of type int, is taken as the precision. If it is negative, it is as if there was no Precision.

FormatChar
's'
The corresponding argument is formatted in a manner consistent with its type:
bool
The result is 'true' or 'false'.
integral types
The %d format is used.
floating point types
The %g format is used.
string types
The result is the string converted to UTF-8. A Precision specifies the maximum number of characters to use in the result.
classes derived from Object
The result is the string returned from the class instance's .toString() method. A Precision specifies the maximum number of characters to use in the result.
non-string static and dynamic arrays
The result is [s0, s1, ...] where sk is the kth element formatted with the default format.

'c'
The corresponding argument must be a character type.

'b','d','o','x','X'
The corresponding argument must be an integral type and is formatted as an integer. If the argument is a signed type and the FormatChar is d it is converted to a signed string of characters, otherwise it is treated as unsigned. An argument of type bool is formatted as '1' or '0'. The base used is binary for b, octal for o, decimal for d, and hexadecimal for x or X. x formats using lower case letters, X uppercase. If there are fewer resulting digits than the Precision, leading zeros are used as necessary. If the Precision is 0 and the number is 0, no digits result.

'e','E'
A floating point number is formatted as one digit before the decimal point, Precision digits after, the FormatChar, ±, followed by at least a two digit exponent: d.dddddde±dd. If there is no Precision, six digits are generated after the decimal point. If the Precision is 0, no decimal point is generated.

'f','F'
A floating point number is formatted in decimal notation. The 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 Precision is zero, no decimal point is generated.

'g','G'
A floating point number is formatted in either e or f format for g; E or F format for G. The f format is used if the exponent for an e format is greater than -5 and less than the Precision. The 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.

'a','A'
A floating point number is formatted in hexadecimal exponential notation 0xh.hhhhhhp±d. There is one hexadecimal digit before the decimal point, and as many after as specified by the Precision. If the Precision is zero, no decimal point is generated. If there is no 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 h.hhhhhh*2±d. The exponent for zero is zero. The hexadecimal digits, x and p are in upper case if the FormatChar is upper case.

Floating point NaN's are formatted as nan if the FormatChar is lower case, or NAN if upper. Floating point infinities are formatted as inf or infinity if the FormatChar is lower case, or INF or INFINITY if upper.

Examples:
import std.c.stdio;
import std.format;

void main()
{
    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:
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 %| 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:
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:
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 '-' flag to "%(".
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:
My friends are ["John", "Nancy"].
My friends are "John", "Nancy".
My friends are John, Nancy.

uint formattedRead(R, Char, S...)(ref R r, const(Char)[] fmt, S args);
Reads characters from input range r, converts them according to fmt, and writes them to args.

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.

Example:
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);

struct FormatSpec(Char) if (is(Unqual!(Char) == Char));
A General handler for printf style format specifiers. Used for building more specific formatting functions.

Example:
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');

int width;
Minimum width, default 0.

int precision;
Precision. Its semantics depends on the argument type. For floating point numbers, precision dictates the number of decimals printed.

int DYNAMIC;
Special value for width and precision. DYNAMIC width or precision means that they were specified with '*' in the format string and are passed at runtime through the varargs.

int UNSPECIFIED;
Special value for precision, meaning the format specifier contained no explicit precision.

char spec;
The actual format specifier, 's' by default.

ubyte indexStart;
Index of the argument for positional parameters, from 1 to ubyte.max. (0 means not used).

ubyte indexEnd;
Index of the last argument for positional parameter range, from 1 to ubyte.max. (0 means not used).

bool flDash;
The format specifier contained a '-' (printf compatibility).

bool flZero;
The format specifier contained a '0' (printf compatibility).

bool flSpace;
The format specifier contained a ' ' (printf compatibility).

bool flPlus;
The format specifier contained a '+' (printf compatibility).

bool flHash;
The format specifier contained a '#' (printf compatibility).

const(Char)[] nested;
In case of a compound format specifier starting with "%(" and ending with "%)", nested contains the string contained within the two separators.

const(Char)[] sep;
In case of a compound format specifier, sep contains the string positioning after "%|".

const(Char)[] trailing;
trailing contains the rest of the format string.

this(in Char[] fmt);
Construct a new FormatSpec using the format string fmt, no processing is done until needed.

FormatSpec!(Char) singleSpec(Char)(Char[] fmt);
Helper function that returns a FormatSpec for a single specifier given in fmt

Returns a FormatSpec with the specifier parsed.

Enforces giving only one specifier to the function.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
bools are formatted as "true" or "false" with %s and as "1" or "0" with integral-specific format specs.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
null literal is formatted as "null".

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Integrals are formatted like printf does.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Floating-point values are formatted like printf does.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Individual characters (char, wchar, or dchar) are formatted as Unicode characters with %s and as integers with integral-specific format specs.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Strings are formatted like printf does.

void formatValue(Writer, T, Char)(Writer w, auto ref T obj, ref FormatSpec!(Char) f);
Static-size arrays are formatted as dynamic arrays.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Dynamic arrays are formatted as input ranges.

Specializations:
  • void[] is formatted like ubyte[].
  • Const array is converted to input range by removing its qualifier.

void formatValue(Writer, T, Char)(Writer w, T obj, ref FormatSpec!(Char) f);
Associative arrays are formatted by using ':' and ', ' as separators, and enclosed by '[' and ']'.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
void formatValue(Writer, T, Char)(Writer w, auto ref T val, ref FormatSpec!(Char) f);
Aggregates (struct, union, class, and interface) are basically formatted by calling toString. 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,
  • If the instance toString has overridden Object.toString, it is used.
  • Otherwise, the objects are formatted as input range.

For the struct and union objects which does not have toString,
  • If they have range interface, formatted as input range.
  • Otherwise, they are formatted like Type(field1, filed2, ...).

Otherwise, are formatted just as their type name.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
enum is formatted like its base value.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Pointers are formatted as hex integers.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Delegates are formatted by 'Attributes ReturnType delegate(Parameters)'

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads a boolean value and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads null literal and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads an integral value and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads a floating-point value and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads one character and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads a string and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads an array (except for string types) and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads an associative array and returns it.

Copyright Digital Mars 2000-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.functional

Functions that manipulate other functions.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Source:
std/functional.d

template unaryFun(alias fun, bool byRef = false, string parmName = "a")
Transforms a string representing an expression into a unary function. The string must use symbol name a as the parameter.

Example:
alias unaryFun!("(a & 1) == 0") isEven;
assert(isEven(2) && !isEven(1));

template binaryFun(alias fun, string parm1Name = "a", string parm2Name = "b")
Transforms a string representing an expression into a Boolean binary predicate. The string must use symbol names a and b as the compared elements.

Example:
alias binaryFun!("a < b") less;
assert(less(1, 2) && !less(2, 1));
alias binaryFun!("a > b") greater;
assert(!greater("1", "2") && greater("2", "1"));

template binaryReverseArgs(alias pred)
Binary predicate that reverses the order of arguments, e.g., given pred(a, b), returns pred(b, a).

template not(alias pred)
Negates predicate pred.

Example:
string a = "   Hello, world!";
assert(find!(not!isWhite)(a) == "Hello, world!");

template curry(alias fun, alias arg)
Curries fun by tying its first argument to a particular value.

Example:
int fun(int a, int b) { return a + b; }
alias curry!(fun, 5) fun5;
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 curry template functions without committing to a particular type of the function.

template adjoin(F...) if (F.length)
Takes multiple functions and adjoins them together. The result is a std.typecons.Tuple with one element per passed-in function. Upon invocation, the returned tuple is the adjoined results of all functions.

Example:
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);

template compose(fun...)
Composes passed-in functions fun[0], fun[1], ... returning a function f(x) that in turn returns fun[0](fun[1](...(x))).... Each function can be a regular functions, a delegate, or a string.

Example:
// 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") == [1, 2, 3]);

template pipe(fun...)
Pipes functions in sequence. Offers the same functionality as 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");

ReturnType!(fun) memoize(alias fun, uint maxSize = (uint).max)(ParameterTypeTuple!(fun) args);
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 this book chapter.

Example:
double transmogrify(int a, string b)
{
   ... expensive computation ...
}
alias memoize!transmogrify fastTransmogrify;
unittest
{
    auto slow = transmogrify(2, "hello");
    auto fast = fastTransmogrify(2, "hello");
    assert(slow == fast);
}

Technically the memoized function should be pure because memoize assumes it will always return the same result for a given tuple of arguments. However, memoize does not enforce that because sometimes it is useful to memoize an impure function, too.

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:

Example:
ulong fib(ulong n)
{
    alias memoize!fib mfib;
    return n < 2 ? 1 : mfib(n - 2) + mfib(n - 1);
}
...
assert(fib(10) == 89);

To improve the speed of the factorial function,

Example:
ulong fact(ulong n)
{
    alias memoize!fact mfact;
    return n < 2 ? 1 : n * mfact(n - 1);
}
...
assert(fact(10) == 3628800);

This memoizes all values of fact up to the largest argument. To only cache the final result, move memoize outside the function as shown below.

Example:
ulong factImpl(ulong n)
{
    return n < 2 ? 1 : n * mfact(n - 1);
}
alias memoize!factImpl fact;
...
assert(fact(10) == 3628800);

The maxSize parameter is a cutoff for the cache size. If upon a miss the length of the hash table is found to be maxSize, the table is simply cleared.

Example:
// Memoize no more than 128 values of transmogrify
alias memoize!(transmogrify, 128) fastTransmogrify;

auto toDelegate(F)(auto ref F fp);
Convert a callable to a delegate with the same parameter list and return type, avoiding heap allocations and use of auxiliary storage.

Examples:
 void doStuff() {
     writeln("Hello, world.");
 }

 void runDelegate(void delegate() myDelegate) {
     myDelegate();
 }

 auto delegateToPass = toDelegate(&doStuff);
 runDelegate(delegateToPass);  // Calls doStuff, prints "Hello, world."

BUGS:
  • Does not work with @safe functions.
  • Ignores C-style / D-style variadic arguments.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.getopt

Processing of command line options.

The getopt module implements a 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.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Credits:
This module and its documentation are inspired by Perl's Getopt::Long module. The syntax of D's getopt is simpler than its Perl counterpart because getopt infers the expected parameter types from the static types of the passed-in pointers.

Source:
std/getopt.d

void getopt(T...)(ref string[] args, T opts);
Synopsis:
import std.getopt;

string data = "file.dat";
int length = 24;
bool verbose;
enum Color { no, yes };
Color color;

void main(string[] args)
{
  getopt(
    args,
    "length",  &length,    // numeric
    "file",    &data,      // string
    "verbose", &verbose,   // flag
    "color",   &color);    // enum
  ...
}

The getopt function takes a reference to the command line (as received by 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 pointed-to by the pointer to its right (the "bound" pointer). The option string in the call to getopt should not start with a dash.

In all cases, the command-line options that were parsed and used by getopt are removed from args. Whatever in the arguments did not look like an option is left in 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 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 ConvException exception is thrown.

Depending on the type of the pointer being bound, getopt recognizes the following kinds of options:

  1. Boolean options. These are the simplest options; all they do is set a Boolean to true:

      bool verbose, debugging;
  getopt(args, "verbose", &verbose, "debug", &debugging);

  2. 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 timeout to 5, invoke the program with either --timeout=5 or --timeout 5.

    • 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+", &paranoid);

      Invoking the program with "--paranoid --paranoid --paranoid" will set 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 paranoid to 42; instead, paranoid is set to 2 and "42" is not considered as part of the normal program arguments.

  3. 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 color to Color.yes, invoke the program with either --color=yes or --color yes.

  4. 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 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'.

  5. 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 outputFiles to [ "myfile.txt", "yourfile.txt" ] .

  6. 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 tuningParms to [ "alpha" : 0.5, "beta" : 0.6 ]. In general, keys and values can be of any parsable types.

  7. Delegate options. An option can be bound to a delegate with the signature void delegate(), void delegate(string option) or void delegate(string option, string value).

    • In the void delegate() case, the delegate is invoked whenever the option is seen.
    • In the void delegate(string option) case, the option string (without the leading dash(es)) is passed to the delegate. 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);
}

    • In the void delegate(string option, string value) case, the option string is handled as an option with one argument, and parsed accordingly. The option and its value are passed to the delegate. After that, whatever was passed to the delegate is considered handled and removed from the list.

      void main(string[] args)
{
  uint verbosityLevel = 1;
  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);
        exit(1);
    }
  }
  getopt(args, "verbosity", &myHandler);
}

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 getopt the 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 getopt, or until the converse directive 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 std.getopt.config.caseSensitive, but not "--Bar", "--bAr" etc. because the directive 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. -t). getopt accepts such parameters seamlessly. When used with a double-dash (e.g. --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 timeout to 5, use either of the following: --timeout=5, --timeout 5, --t=5, --t 5, or -t5. Forms such as -t 5 and -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 "-a -b -c". By default, this confusing option is turned off. You can turn it on with the 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 std.getopt.config.noBundling.

Passing unrecognized options through

If an application needs to do its own processing of whichever arguments getopt did not understand, it can pass the std.getopt.config.passThrough directive to 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 args after getopt returns.

Options Terminator

A lonesome double-dash terminates 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 "--foo -- --bar" parses foo but leaves "--bar" in args. The double-dash itself is removed from the argument array.

enum config;
Configuration options for getopt. You can pass them to getopt in any position, except in between an option string and its bound pointer.

caseSensitive
Turns case sensitivity on

caseInsensitive
Turns case sensitivity off

bundling
Turns bundling on

noBundling
Turns bundling off

passThrough
Pass unrecognized arguments through

noPassThrough
Signal unrecognized arguments as errors

stopOnFirstNonOption
Stop at first argument that does not look like an option

dchar optionChar;
The option character. Defaults to '-' but it can be assigned to prior to calling getopt.

string endOfOptions;
The string that conventionally marks the end of all options. Defaults to "--" but can be assigned to prior to calling getopt. Assigning an empty string to endOfOptions effectively disables it.

dchar assignChar;
The assignment character used in options with parameters. Defaults to '=' but can be assigned to prior to calling getopt.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.json

JavaScript Object Notation

License:
Boost License 1.0.

Authors:
Jeremie Pelletier

References:
http://json.org/

Source:
std/json.d

enum JSON_TYPE;
JSON type enumeration

STRING
INTEGER
Indicates the type of a JSONValue.

UINTEGER
FLOAT
OBJECT
ARRAY
TRUE
FALSE
NULL
integers > 2^63-1

struct JSONValue;
JSON value node

string str;
Value when type is JSON_TYPE.STRING

long integer;
Value when type is JSON_TYPE.INTEGER

ulong uinteger;
Value when type is JSON_TYPE.UINTEGER

real floating;
Value when type is JSON_TYPE.FLOAT

JSONValue[string] object;
Value when type is JSON_TYPE.OBJECT

JSONValue[] array;
Value when type is JSON_TYPE.ARRAY

JSON_TYPE type;
Specifies the type of the value stored in this structure.

ref JSONValue opIndex(size_t i);
array syntax for json arrays

ref JSONValue opIndex(string k);
hash syntax for json objects

JSONValue parseJSON(T)(T json, int maxDepth = -1);
Parses a serialized string and returns a tree of JSON values.

string toJSON(in JSONValue* root);
Takes a tree of JSON values and returns the serialized string.

class JSONException: object.Exception;
Exception thrown on JSON errors

Copyright Jeremie Pelletier 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.math

Elementary mathematical functions

Contains the elementary mathematical functions (powers, roots, and trignometric functions), and low-level floating-point operations. Mathematical special functions are available in std.mathspecial.

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.

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.

License:
Boost License 1.0.

Authors:
Walter Bright, Don Clugston

Source:
std/math.d

real E;
e = 2.718281...

real LOG2T;
log210 = 3.321928...

real LOG2E;
log2e = 1.442695...

real LOG2;
log102 = 0.301029...

real LOG10E;
log10e = 0.434294...

real LN2;
ln 2 = 0.693147...

real LN10;
ln 10 = 2.302585...

real PI;
π = 3.141592...

real PI_2;
π / 2 = 1.570796...

real PI_4;
π / 4 = 0.785398...

real M_1_PI;
1 / π = 0.318309...

real M_2_PI;
2 / π = 0.636619...

real M_2_SQRTPI;
2 / √π = 1.128379...

real SQRT2;
√2 = 1.414213...

real SQRT1_2;
√½ = 0.707106...

pure nothrow @safe Num abs(Num)(Num x);
pure nothrow @safe real abs(Num)(Num y);
Calculates the absolute value

For complex numbers, abs(z) = sqrt( z.re2 + z.im2 ) = hypot(z.re, z.im).

pure nothrow @safe creal conj(creal z);
pure nothrow @safe ireal conj(ireal y);
Complex conjugate

conj(x + iy) = x - iy

Note that z * conj(z) = z.re2 - z.im2 is always a real number

pure nothrow @safe real cos(real x);
Returns cosine of x. x is in radians.

Special Values
x | cos(x) | invalid?
NAN | NAN | yes
±∞ NAN yes

BUGS:
Results are undefined if |x| >= 264.

pure nothrow @safe real sin(real x);
Returns sine of x. x is in radians.

Special Values
x | sin(x) | invalid?
NAN | NAN | yes
±0.0 | ±0.0 | no
±∞ NAN yes

BUGS:
Results are undefined if |x| >= 264.

pure nothrow @safe creal sin(creal z);
pure nothrow @safe ireal sin(ireal y);
sine, complex and imaginary

sin(z) = sin(z.re)*cosh(z.im) + cos(z.re)*sinh(z.im)i

If both sin(θ) and cos(θ) are required, it is most efficient to use expi(θ).

pure nothrow @safe creal cos(creal z);
pure nothrow @safe real cos(ireal y);
cosine, complex and imaginary

cos(z) = cos(z.re)*cosh(z.im) - sin(z.re)*sinh(z.im)i

pure nothrow @trusted real tan(real x);
Returns tangent of x. x is in radians.

Special Values
x | tan(x) | invalid?
NAN | NAN | yes
±0.0 | ±0.0 | no
±∞ NAN yes

pure nothrow @safe real acos(real x);
pure nothrow @safe double acos(double x);
pure nothrow @safe float acos(float x);
Calculates the arc cosine of x, returning a value ranging from 0 to π.

Special Values
x | acos(x) | invalid?
>1.0 | NAN | yes
<-1.0 | NAN | yes
NAN | NAN | yes

pure nothrow @safe real asin(real x);
pure nothrow @safe double asin(double x);
pure nothrow @safe float asin(float x);
Calculates the arc sine of x, returning a value ranging from -π/2 to π/2.

Special Values
x | asin(x) | invalid?
±0.0 | ±0.0 | no
>1.0 | NAN | yes
<-1.0 | NAN | yes

pure nothrow @safe real atan(real x);
pure nothrow @safe double atan(double x);
pure nothrow @safe float atan(float x);
Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2.

Special Values
x | atan(x) | invalid?
±0.0 | ±0.0 | no
±∞ NAN yes

pure nothrow @trusted real atan2(real y, real x);
pure nothrow @safe double atan2(double y, double x);
pure nothrow @safe float atan2(float y, float x);
Calculates the arc tangent of y / x, returning a value ranging from -π to π.

Special Values
y | x | atan(y, x)
NAN | anything | NAN
anything | NAN | NAN
±0.0 | >0.0 | ±0.0
±0.0 | +0.0 | ±0.0
±0.0 | <0.0 | ±π
±0.0 | -0.0 | ±π
>0.0 | ±0.0 | π/2
<0.0 | ±0.0 | -π/2
>0.0 ∞ ±0.0
±∞ anything ±π/2
>0.0 -∞ ±π
±∞ ∞ ±π/4
±∞ -∞ ±3π/4

pure nothrow @safe real cosh(real x);
pure nothrow @safe double cosh(double x);
pure nothrow @safe float cosh(float x);
Calculates the hyperbolic cosine of x.

Special Values
x cosh(x) invalid?
±∞ ±0.0 no

pure nothrow @safe real sinh(real x);
pure nothrow @safe double sinh(double x);
pure nothrow @safe float sinh(float x);
Calculates the hyperbolic sine of x.

Special Values
x | sinh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±∞ no

pure nothrow @safe real tanh(real x);
pure nothrow @safe double tanh(double x);
pure nothrow @safe float tanh(float x);
Calculates the hyperbolic tangent of x.

Special Values
x | tanh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±1.0 no

pure nothrow @safe real acosh(real x);
pure nothrow @safe double acosh(double x);
pure nothrow @safe float acosh(float x);
Calculates the inverse hyperbolic cosine of x.

Mathematically, acosh(x) = log(x + sqrt( x*x - 1))

Special Values
x | acosh(x)
NAN | NAN
<1 | NAN
1 | 0
+∞ +∞

pure nothrow @safe real asinh(real x);
pure nothrow @safe double asinh(double x);
pure nothrow @safe float asinh(float x);
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

Special Values
x | asinh(x)
NAN | NAN
±0 | ±0
±∞ ±∞

pure nothrow @safe real atanh(real x);
pure nothrow @safe double atanh(double x);
pure nothrow @safe float atanh(float x);
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

Special Values
x | acosh(x)
NAN | NAN
±0 | ±0
-∞ -0

pure nothrow @safe long rndtol(real x);
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.

real rndtonl(real x);
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.

pure nothrow @safe float sqrt(float x);
pure nothrow @safe double sqrt(double x);
pure nothrow @safe real sqrt(real x);
Compute square root of x.

Special Values
x | sqrt(x) | invalid?
-0.0 | -0.0 | no
<0.0 | NAN | yes
+∞ +∞ no

pure nothrow @trusted real exp(real x);
pure nothrow @safe double exp(double x);
pure nothrow @safe float exp(float x);
Calculates ex.

Special Values
x | ex
+∞ +∞
-∞ +0.0
NAN | NAN

pure nothrow @trusted real expm1(real x);
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.

Special Values
x | ex-1
±0.0 | ±0.0
+∞ +∞
-∞ -1.0
NAN | NAN

pure nothrow @trusted real exp2(real x);
Calculates 2x.

Special Values
x | exp2(x)
+∞ +∞
-∞ +0.0
NAN | NAN

pure nothrow @trusted creal expi(real y);
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.

pure nothrow @trusted real frexp(real value, out int exp);
Separate floating point value into significand and exponent.

Returns:
Calculate and return x and exp such that value =x*2exp and .5 <= |x| < 1.0

x has same sign as value.

Special Values
value | returns | exp
±0.0 | ±0.0 | 0
+∞ +∞ int.max
-∞ -∞ int.min
±NAN | ±NAN | int.min

nothrow @trusted int ilogb(real x);
Extracts the exponent of x as a signed integral value.

If x is not a special value, the result is the same as cast(int)logb(x).

Special Values
x | ilogb(x) | Range error?
0 | FP_ILOGB0 | yes
±∞ int.max no
NAN | FP_ILOGBNAN | no

pure nothrow @safe real ldexp(real n, int exp);
Compute n * 2exp

References:
frexp

pure nothrow @safe real log(real x);
Calculate the natural logarithm of x.

Special Values
x | log(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

pure nothrow @safe real log10(real x);
Calculate the base-10 logarithm of x.

Special Values
x | log10(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

pure nothrow @safe real log1p(real x);
Calculates the natural logarithm of 1 + x.

For very small x, log1p(x) will be more accurate than log(1 + x).

Special Values
x | log1p(x) | divide by 0? | invalid?
±0.0 | ±0.0 | no | no
-1.0 -∞ yes no
<-1.0 | NAN | no | yes
+∞ -∞ no no

pure nothrow @safe real log2(real x);
Calculates the base-2 logarithm of x: log2x

Special Values
x | log2(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

nothrow @trusted real logb(real x);
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 <= x * FLT_RADIX-logb(x) < FLT_RADIX

Special Values
x logb(x) divide by 0?
±∞ +∞ no
±0.0 -∞ yes

nothrow @trusted real fmod(real x, real y);
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.

Special Values
x | y | fmod(x, y) | invalid?
±0.0 | not 0.0 | ±0.0 | no
±∞ anything NAN yes
anything | ±0.0 | NAN | yes
!=±∞ ±∞ x no

nothrow @trusted real modf(real x, ref real i);
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.

Special Values
x i (on input) modf(x, i) i (on return)
±∞ anything ±0.0 ±∞

nothrow @trusted real scalbn(real x, int n);
Efficiently calculates x * 2n.

scalbn handles underflow and overflow in the same fashion as the basic arithmetic operators.

Special Values
x | scalb(x)
±∞ ±∞
±0.0 | ±0.0

nothrow @trusted real cbrt(real x);
Calculates the cube root of x.

Special Values
x | cbrt(x) | invalid?
±0.0 | ±0.0 | no
NAN | NAN | yes
±∞ ±∞ no

pure nothrow @safe real fabs(real x);
Returns |x|

Special Values
x | fabs(x)
±0.0 | +0.0
±∞ +∞

pure nothrow @safe real hypot(real x, real y);
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(x2 + y2)

Note that hypot(x, y), hypot(y, x) and hypot(x, -y) are equivalent.

Special Values
x y hypot(x, y) invalid?
x ±0.0 |x| no
±∞ y +∞ no
±∞ NAN +∞ no

nothrow @trusted real ceil(real x);
Returns the value of x rounded upward to the next integer (toward positive infinity).

nothrow @trusted real floor(real x);
Returns the value of x rounded downward to the next integer (toward negative infinity).

nothrow @trusted real nearbyint(real x);
Rounds x to the nearest integer value, using the current rounding mode.

Unlike the rint functions, nearbyint does not raise the FE_INEXACT exception.

pure nothrow @safe real rint(real 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. nearbyint performs the same operation, but does not set the FE_INEXACT exception.

pure nothrow @trusted long lrint(real x);
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.

nothrow @trusted real round(real 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 to the even integer.

nothrow @trusted long lround(real 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.

nothrow @trusted real trunc(real x);
Returns the integer portion of x, dropping the fractional portion.

This is also known as "chop" rounding.

nothrow @trusted real remainder(real x, real y);
nothrow @trusted real remquo(real x, real y, out int n);
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.

Special Values
x | y | remainder(x, y) | n | invalid?
±0.0 | not 0.0 | ±0.0 | 0.0 | no
±∞ anything NAN ? yes
anything ±0.0 NAN ? yes
!= ±∞ ±∞ x ? no

Note:
remquo not supported on windows

struct IeeeFlags;
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.

Example:
    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);

@property bool inexact();
The result cannot be represented exactly, so rounding occured. (example: x = sin(0.1); )

@property bool underflow();
A zero was generated by underflow (example: x = real.min*real.epsilon/2;)

@property bool overflow();
An infinity was generated by overflow (example: x = real.max*2;)

@property bool divByZero();
An infinity was generated by division by zero (example: x = 3/0.0; )

@property bool invalid();
A machine NaN was generated. (example: x = real.infinity * 0.0; )

void resetIeeeFlags();
Set all of the floating-point status flags to false.

@property IeeeFlags ieeeFlags();
Return a snapshot of the current state of the floating-point status flags.

struct FloatingPointControl;
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 division by zero, overflow, and invalid operation exceptions are enabled. These three are combined into a severeExceptions value for convenience. Note in particular that if 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:
  {
    // Enable hardware exceptions for division by zero, overflow to infinity,
    // invalid operations, and uninitialized floating-point variables.

    FloatingPointControl fpctrl;
    fpctrl.enableExceptions(FloatingPointControl.severeExceptions);

    double y = x*3.0; // will generate a hardware exception, if x is uninitialized.
    //
    fpctrl.rounding = FloatingPointControl.roundUp;

    // The hardware exceptions will be disabled when leaving this scope.
    // The original rounding mode will also be restored.
  }

severeExceptions
Severe = The overflow, division by zero, and invalid exceptions.

void enableExceptions(uint exceptions);
Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together.

void disableExceptions(uint exceptions);
Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together.

@property void rounding(RoundingMode newMode);
Change the floating-point hardware rounding mode

static @property uint enabledExceptions();
Return the exceptions which are currently enabled (unmasked)

static @property RoundingMode rounding();
Return the currently active rounding mode

pure nothrow @trusted bool isNaN(real x);
Returns !=0 if e is a NaN.

pure nothrow @trusted int isFinite(real e);
Returns !=0 if e is finite (not infinite or NAN).

pure nothrow @trusted int isNormal(X)(X x);
Returns !=0 if x is normalized (not zero, subnormal, infinite, or NAN).

pure nothrow @trusted int isSubnormal(float f);
pure nothrow @trusted int isSubnormal(double d);
pure nothrow @trusted int isSubnormal(real x);
Is number subnormal? (Also called "denormal".) Subnormals have a 0 exponent and a 0 most significant mantissa bit.

pure nothrow @trusted bool isInfinity(real x);
Return !=0 if e is ±∞.

pure nothrow @trusted bool isIdentical(real x, real y);
Is the binary representation of x identical to y?

Same as ==, except that positive and negative zero are not identical, and two NANs are identical if they have the same 'payload'.

pure nothrow @trusted int signbit(real x);
Return 1 if sign bit of e is set, 0 if not.

pure nothrow @trusted real copysign(real to, real from);
Return a value composed of to with from's sign bit.

pure nothrow @safe F sgn(F)(F x);
Returns -1 if x < 0, x if x == 0, 1 if x > 0, and NAN if x==NAN.

pure nothrow @trusted real NaN(ulong payload);
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.

pure nothrow @trusted ulong getNaNPayload(real x);
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.

pure nothrow @trusted real nextUp(real x);
pure nothrow @trusted double nextUp(double x);
pure nothrow @trusted float nextUp(float x);
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.

Special Values
x | nextUp(x)
-∞ -real.max
±0.0 | real.min_normal*real.epsilon
real.max ∞
∞ ∞
NAN | NAN

pure nothrow @safe real nextDown(real x);
pure nothrow @safe double nextDown(double x);
pure nothrow @safe float nextDown(float 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.

Special Values
x | nextDown(x)
∞ real.max
±0.0 | -real.min_normal*real.epsilon
-real.max -∞
-∞ -∞
NAN | NAN

pure nothrow @safe T nextafter(T)(T x, T y);
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.

pure nothrow @safe real fdim(real x, real y);
Returns the positive difference between x and y.

Returns:
Special Values
x, y | fdim(x, y)
x > y | x - y
x <= y | +0.0

pure nothrow @safe real fmax(real x, real y);
Returns the larger of x and y.

pure nothrow @safe real fmin(real x, real y);
Returns the smaller of x and y.

pure nothrow @safe real fma(real x, real y, real z);
Returns (x * y) + z, rounding only once according to the current rounding mode.

BUGS:
Not currently implemented - rounds twice.

pure nothrow @trusted Unqual!(F) pow(F, G)(F x, G n);
Compute the value of x n, where n is an integer

pure nothrow @trusted typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n);
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.

pure nothrow @trusted real pow(I, F)(I x, F y);
Computes integer to floating point powers.

pure nothrow @trusted Unqual!(Largest!(F, G)) pow(F, G)(F x, G y);
Calculates xy.

Special Values
x | y | pow(x, y) | div 0 | invalid?
anything | ±0.0 | 1.0 | no | no
|x| > 1 +∞ +∞ no no
|x| < 1 +∞ +0.0 no no
|x| > 1 -∞ +0.0 no no
|x| < 1 -∞ +∞ no no
+∞ > 0.0 +∞ no no
+∞ < 0.0 +0.0 no no
-∞ odd integer > 0.0 -∞ no no
-∞ > 0.0, not odd integer +∞ no no
-∞ odd integer < 0.0 -0.0 no no
-∞ < 0.0, not odd integer +0.0 no no
±1.0 ±∞ NAN no yes
< 0.0 | finite, nonintegral | NAN | no | yes
±0.0 odd integer < 0.0 ±∞ yes no
±0.0 < 0.0, not odd integer +∞ yes no
±0.0 | odd integer > 0.0 | ±0.0 | no | no
±0.0 | > 0.0, not odd integer | +0.0 | no | no

pure nothrow @trusted int feqrel(X)(X x, X y);
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.

Special Values
x | y | feqrel(x, y)
x | x | real.mant_dig
x | >= 2*x | 0
x | <= x/2 | 0
NAN | any | 0
any | NAN | 0

pure nothrow @trusted real poly(real x, const real[] A);
Evaluate polynomial A(x) = a0 + a1x + a2x2 + a3x3; ...

Uses Horner's rule A(x) = a0 + x(a1 + x(a2 + x(a3 + ...)))

Parameters:
real[] A array of coefficients a0, a1, etc.

bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 1e-05);
Computes whether lhs is approximately equal to rhs admitting a maximum relative difference maxRelDiff and a maximum absolute difference maxAbsDiff.

If the two inputs are ranges, approxEqual returns true if and only if the ranges have the same number of elements and if approxEqual evaluates to true for each pair of elements.

bool approxEqual(T, U)(T lhs, U rhs);
Returns approxEqual(lhs, rhs, 1e-2, 1e-5).

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.mathspecial

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.

License:
Boost License 1.0.

Authors:
Stephen L. Moshier (original C code). Conversion to D by Don Clugston

Source:
std/mathspecial.d

real gamma(real x);
The Gamma function, Γ(x)

Γ(x) is a generalisation of the factorial function to real and complex numbers. Like x!, Γ(x+1) = x * Γ(x).

Mathematically, if z.re > 0 then Γ(z) = ∫0∞ tz-1e-t dt

Special Values
x | Γ(x)
NAN | NAN
±0.0 ±∞
integer > 0 | (x-1)!
integer < 0 | NAN
+∞ +∞
-∞ NAN

real logGamma(real x);
Natural logarithm of the gamma function, Γ(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))).

Special Values
x | logGamma(x)
NAN | NAN
integer <= 0 +∞
±∞ +∞

real sgnGamma(real x);
The sign of Γ(x).

Returns -1 if Γ(x) < 0, +1 if Γ(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 beta(real x, real y);
Beta function

The beta function is defined as

beta(x, y) = (Γ(x) * Γ(y)) / Γ(x + y)

real digamma(real x);
Digamma function

The digamma function is the logarithmic derivative of the gamma function.

digamma(x) = d/dx logGamma(x)

real betaIncomplete(real a, real b, real 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) = Γ(a + b) / ( Γ(a) Γ(b) ) * ∫0x ta-1(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 betaIncompleteInverse(real a, real b, real y);
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 gammaIncomplete(real a, real x);
real gammaIncompleteCompl(real a, real x);
Incomplete gamma integral and its complement

These functions are defined by

gammaIncomplete = ( ∫0x e-t ta-1 dt )/ Γ(a)

gammaIncompleteCompl(a,x) = 1 - gammaIncomplete(a,x) = (∫x∞ e-t ta-1 dt )/ Γ(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 gammaIncompleteComplInverse(real a, real p);
Inverse of complemented incomplete gamma integral

Given a and p, the function finds x such that

gammaIncompleteCompl( a, x ) = p.

real erf(real x);
Error function

The integral is

erf(x) = 2/ √(π) ∫0x exp( - t2) 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 erfc(real x);
Complementary error function

erfc(x) = 1 - erf(x) = 2/ √(π) ∫x∞ exp( - t2) dt

This function has high relative accuracy for values of x far from zero. (For values near zero, use erf(x)).

real normalDistribution(real x);
Normal distribution function.

The normal (or Gaussian, or bell-shaped) distribution is defined as:

normalDist(x) = 1/√ π ∫-∞x exp( - t2/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:
http://www.netlib.org/cephes/ldoubdoc.html, G. Marsaglia, "Evaluating the Normal Distribution", Journal of Statistical Software 11, (July 2004).

real normalDistributionInverse(real p);
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.

Based on the CEPHES math library, which is Copyright (C) 1994 Stephen L. Moshier (moshier@world.std.com). | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.metastrings

Templates with which to do compile-time manipulation of strings.

License:
Boost License 1.0.

Authors:
Walter Bright, Don Clugston

Source:
std/metastrings.d

template Format(A...)
Formats constants into a string at compile time. Analogous to std.string.format.

Parameters:
A = tuple of constants, which can be strings, characters, or integral values.

Formats:
The formats supported are %s for strings, and %% for the % character.

Example:
import std.metastrings;
import std.stdio;

void main()
{
  string s = Format!("Arg %s = %s", "foo", 27);
  writefln(s); // "Arg foo = 27"
}

template toStringNow(ulong v)
template toStringNow(long v)
template toStringNow(uint U)
template toStringNow(int I)
template toStringNow(bool B)
template toStringNow(string S)
template toStringNow(char C)
Convert constant argument to a string.

template parseUinteger(const(char)[] s)
Parse unsigned integer literal from the start of string s.

Returns:
.value = the integer literal as a string, .rest = the string following the integer literal

Otherwise:
.value = null, .rest = s

template parseInteger(const(char)[] s)
Parse integer literal optionally preceded by '-' from the start of string s.

Returns:
.value = the integer literal as a string, .rest = the string following the integer literal

Otherwise:
.value = null, .rest = s

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.mmfile

Read and write memory mapped files.

License:
Boost License 1.0.

Authors:
Walter Bright, Matthew Wilson

Source:
std/mmfile.d

class MmFile;
MmFile objects control the memory mapped file resource.

enum Mode;
The mode the memory mapped file is opened with.

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

this(string filename);
Open memory mapped file filename for reading. File is closed when the object instance is deleted.

Throws:
std.file.FileException

this(string filename, Mode mode, ulong size, void* address, size_t window = 0);
Open memory mapped file filename in mode. File is closed when the object instance is deleted.

Parameters:
string filename | name of the file. If null, an anonymous file mapping is created.
Mode mode | access mode defined above.
ulong size | the size of the file. If 0, it is taken to be the size of the existing file.
void* address | the preferred address to map the file to, although the system is not required to honor it. If null, the system selects the most convenient address.
size_t window | preferred block size of the amount of data to map at one time with 0 meaning map the entire file. The window size must be a multiple of the memory allocation page size.

Throws:
std.file.FileException

const @property ulong length();
Gives size in bytes of the memory mapped file.

Mode mode();
Read-only property returning the file mode.

void[] opSlice();
Returns entire file contents as an array.

void[] opSlice(ulong i1, ulong i2);
Returns slice of file contents as an array.

ubyte opIndex(ulong i);
Returns byte at index i in file.

ubyte opIndexAssign(ubyte value, ulong i);
Sets and returns byte at index i in file to value.

Copyright Digital Mars 2004 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.numeric

This module is a port of a growing fragment of the numeric header in Alexander Stepanov's Standard Template Library, with a few additions.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, Don Clugston, Robert Jacques

Source:
std/numeric.d

enum CustomFloatFlags;
Format flags for CustomFloat.

signed
Adds a sign bit to allow for signed numbers.

storeNormalized
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. 1.nnnn instead of 0.nnnn. True for all IEE754 types

allowDenorm
Stores the significand in IEEE754 denormalized form when the exponent is 0. Required to express the value 0.

infinity
Allows the storage of IEEE754 infinity values.

nan
Allows the storage of IEEE754 Not a Number values.

probability
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.

negativeUnsigned
If set, unsigned custom floats are assumed to be negative.

allowDenormZeroOnly
If set, 0 is the only allowed IEEE754 denormalized number. Requires allowDenorm and storeNormalized.

ieee
Include all of the IEEE754 options.

none
Include none of the above options.

template CustomFloat(uint bits) if (bits == 8 || bits == 16 || bits == 32 || bits == 64 || bits == 80)
template CustomFloat(uint precision, uint exponentWidth, CustomFloatFlags flags = CustomFloatFlags.ieee) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0)
struct CustomFloat(uint precision, uint exponentWidth, CustomFloatFlags flags, uint bias) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 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 real first. After the operation is completed the result can be stored in a custom floating-point value via assignment.

Example:
 // 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;
 writeln(w);

 // Functions calls require conversion
 z = sin(+x)           + cos(+y);                     // Use uniary plus to concisely convert to a real
 z = sin(x.re)         + cos(y.re);                   // Or use the .re property to 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 CustomFloat!(4, 4, CustomFloatFlags.ieee^CustomFloatFlags.probability^CustomFloatFlags.signed ) Probability;
 auto p = Probability(0.5);

template FPTemporary(F) if (isFloatingPoint!(F))
Defines the fastest type to use when storing temporaries of a calculation intended to ultimately yield a result of type F (where F must be one of float, double, or real). When doing a multi-step computation, you may want to store intermediate results as FPTemporary!F.

Example:
// 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;
}

The necessity of 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 real precision internally. In that case, storing the intermediate result in double format is not only less precise, it is also (surprisingly) slower, because a conversion from real to double is performed every pass through the loop. This being a lose-lose situation, FPTemporary!F has been defined as the fastest type to use for calculations at precision F. There is no need to define a type for the most accurate calculations, as that is always real.

Finally, there is no guarantee that using FPTemporary!F will always be fastest, as the speed of floating-point calculations depends on very many factors.

template secantMethod(alias fun)
Implements the secant method for finding a root of the function fun starting from points [xn_1, x_n] (ideally close to the root). Num may be float, double, or real.

Example:
float f(float x) {
    return cos(x) - x*x*x;
}
auto x = secantMethod!(f)(0f, 1f);
assert(approxEqual(x, 0.865474));

T findRoot(T, R)(scope R delegate(T) f, T a, T b);
Find a real root of a real function f(x) via bracketing.

Given a function f and a range [a..b] such that f(a) and f(b) have opposite signs, returns the value of x in the range which is closest to a root of f(x). If f(x) has more than one root in the range, one will be chosen arbitrarily. If 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 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 www.netlib.org as algorithm TOMS478.

Tuple!(T, T, R, R) findRoot(T, R)(scope R delegate(T) f, T ax, T bx, R fax, R fbx, scope bool delegate(T lo, T hi) tolerance);
Find root of a real function f(x) by bracketing, allowing the termination condition to be specified.

Parameters:
f | Function to be analyzed
ax | Left bound of initial range of f known to contain the root.
bx | Right bound of initial range of f known to contain the root.
fax | Value of f(ax).
fbx | Value of f(bx). (f(ax) and 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 true when these bounds are acceptable. If this function always returns false, full machine precision will be achieved.

Returns:
A tuple consisting of two ranges. The first two elements are the range (in 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.

CommonType!(ElementType!(Range1), ElementType!(Range2)) euclideanDistance(Range1, Range2)(Range1 a, Range2 b);
CommonType!(ElementType!(Range1), ElementType!(Range2)) euclideanDistance(Range1, Range2, F)(Range1 a, Range2 b, F limit);
Computes Euclidean distance between input ranges a and 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 limit (this is useful to save computation if a small distance is sought).

CommonType!(ElementType!(Range1), ElementType!(Range2)) dotProduct(Range1, Range2)(Range1 a, Range2 b);
Unqual!(CommonType!(F1, F2)) dotProduct(F1, F2)(in F1[] avector, in F2[] bvector);
Computes the dot product of input ranges a and 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)) cosineSimilarity(Range1, Range2)(Range1 a, Range2 b);
Computes the cosine similarity of input ranges a and 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.

bool normalize(R)(R range, ElementType!(R) sum = 1);
Normalizes values in range by multiplying each element with a number chosen such that values sum up to sum. If elements in range sum to zero, assigns sum / range.length to all. Normalization makes sense only if all elements in range are positive. normalize assumes that is the case without checking it.

Returns:
true if normalization completed normally, false if all elements in range were zero or if range is empty.

ElementType!(Range) entropy(Range)(Range r);
ElementType!(Range) entropy(Range, F)(Range r, F max);
Computes entropy of input range r in bits. This function assumes (without checking) that the values in r are all in [0, 1]. For the entropy to be meaningful, often 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 max.

CommonType!(ElementType!(Range1), ElementType!(Range2)) kullbackLeiblerDivergence(Range1, Range2)(Range1 a, Range2 b);
Computes the Kullback-Leibler divergence between input ranges a and b, which is the sum ai * log(ai / bi). The base of logarithm is 2. The ranges are assumed to contain elements in [0, 1]. Usually the ranges are normalized probability distributions, but this is not required or checked by kullbackLeiblerDivergence. If any element bi is zero and the corresponding element ai nonzero, returns infinity. (Otherwise, if ai == 0 && bi == 0, the term ai * log(ai / bi) is considered zero.) If the inputs are normalized, the result is positive.

CommonType!(ElementType!(Range1), ElementType!(Range2)) jensenShannonDivergence(Range1, Range2)(Range1 a, Range2 b);
CommonType!(ElementType!(Range1), ElementType!(Range2)) jensenShannonDivergence(Range1, Range2, F)(Range1 a, Range2 b, F limit);
Computes the Jensen-Shannon divergence between a and b, which is the sum (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 [0, 1]. Usually the ranges are normalized probability distributions, but this is not required or checked by jensenShannonDivergence. If the inputs are normalized, the result is bounded within [0, 1]. The three-parameter version stops evaluations as soon as the intermediate result is greater than or equal to limit.

F gapWeightedSimilarity(alias comp = "a == b", R1, R2, F)(R1 s, R2 t, F lambda);
The so-called "all-lengths gap-weighted string kernel" computes a similarity measure between s and t based on all of their common subsequences of all lengths. Gapped subsequences are also included.

To understand what gapWeightedSimilarity(s, t, lambda) computes, consider first the case lambda = 1 and the strings s = ["Hello", "brave", "new", "world"] and t = ["Hello", "new", "world"]. In that case, gapWeightedSimilarity counts the following matches:

  1. three matches of length 1, namely "Hello", "new", and "world";
  2. three matches of length 2, namely ("Hello", "new"), ("Hello", "world"), and ("new", "world");
  3. one match of length 3, namely ("Hello", "new", "world").

The call 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 ("Hello", "new") is deemed as good a match as ("new", "world"). This may be too permissive for some applications. To eliminate gapped matches entirely, use 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 ("Hello", "new"), ("Hello", "world"), and ("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 lambda between 0 and 1 enter into play: gapped matches are exponentially penalized with the number of gaps with base lambda. This means that an ungapped match adds 1 to the return value; a match with one gap in either string adds lambda to the return value; ...; a match with a total of n gaps in both strings adds 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 ("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 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);

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. gapWeightedSimilarity uses a highly optimized dynamic programming implementation that needs 16 * min(s.length, t.length) extra bytes of memory and Ο(s.length * t.length) time to complete.

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);
The similarity per 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 ["Hello", "world"] is increasingly similar with the range ["Hello", "world", "world", "world",...] as more instances of "world" are appended. To prevent that, gapWeightedSimilarityNormalized computes a normalized version of the similarity that is computed as gapWeightedSimilarity(s, t, lambda) / sqrt(gapWeightedSimilarity(s, t, lambda) * gapWeightedSimilarity(s, t, lambda)). The function gapWeightedSimilarityNormalized (a so-called normalized kernel) is bounded in [0, 1], reaches 0 only for ranges that don't match in any position, and 1 only for identical ranges.

Example:
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(gapWeightedSimilarityNormalized(s, t, 1) == 7. / sqrt(15. * 7));

The optional parameters sSelfSim and tSelfSim are meant for avoiding duplicate computation. Many applications may have already computed gapWeightedSimilarity(s, s, lambda) and/or gapWeightedSimilarity(t, t, lambda). In that case, they can be passed as sSelfSim and tSelfSim, respectively.

struct GapWeightedSimilarityIncremental(Range, F = double) if (isRandomAccessRange!(Range) && hasLength!(Range));
GapWeightedSimilarityIncremental!(R, F) gapWeightedSimilarityIncremental(R, F)(R r1, R r2, F penalty);
Similar to 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 Ο(s.length * t.length). The time complexity is Ο(s.length * t.length) time for computing each step. Continuing on the previous example:

string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
auto simIter = gapWeightedSimilarityIncremental(s, t, 1);
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

The implementation is based on the pseudocode in Fig. 4 of the paper "Efﬁcient Computation of Gapped Substring Kernels on Large Alphabets" by Rousu et al., with additional algorithmic and systems-level optimizations.

this(Range s, Range t, F lambda);
Constructs an object given two ranges s and t and a penalty lambda. Constructor completes in Ο(s.length * t.length) time and computes all matches of length 1.

GapWeightedSimilarityIncremental opSlice();
Returns this.

void popFront();
Computes the match of the popFront length. Completes in Ο(s.length * t.length) time.

F front();
Returns the gapped similarity at the current match length (initially 1, grows with each call to popFront).

bool empty();
Returns whether there are more matches.

T gcd(T)(T a, T b);
Computes the greatest common divisor of a and b by using Euler's algorithm.

class Fft;
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:
en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm

this(size_t size);
Create an Fft object for computing fast Fourier transforms of power of two sizes of size or smaller. size must be a power of two.

const Complex!(F)[] fft(F = double, R)(R range);
Compute the Fourier transform of range using the Ο(N log N) Cooley-Tukey Algorithm. range must be a random-access range with slicing and a length equal to 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 .re and .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.

const void fft(Ret, R)(R range, Ret buf);
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.

const Complex!(F)[] inverseFft(F = double, R)(R range);
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.

const void inverseFft(Ret, R)(R range, Ret buf);
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.

Complex!(F)[] fft(F = double, R)(R range);
void fft(Ret, R)(R range, Ret buf);
Complex!(F)[] inverseFft(F = double, R)(R range);
void inverseFft(Ret, R)(R range, Ret buf);
Convenience functions that create an 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.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.outbuffer

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/outbuffer.d

class OutBuffer;
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.

ubyte[] toBytes();
Convert to array of bytes.

void reserve(size_t nbytes);
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 write(const(ubyte)[] bytes);
void write(ubyte b);
void write(byte b);
void write(char c);
void write(dchar c);
void write(ushort w);
void write(short s);
void write(wchar c);
void write(uint w);
void write(int i);
void write(ulong l);
void write(long l);
void write(float f);
void write(double f);
void write(real f);
void write(in char[] s);
void write(OutBuffer buf);
Append data to the internal buffer.

void fill0(size_t nbytes);
Append nbytes of 0 to the internal buffer.

void alignSize(size_t alignsize);
0-fill to align on power of 2 boundary.

void align2();
Optimize common special case alignSize(2)

void align4();
Optimize common special case alignSize(4)

string toString();
Convert internal buffer to array of chars.

void vprintf(string format, va_list args);
Append output of C's vprintf() to internal buffer.

void printf(string format, ...);
Append output of C's printf() to internal buffer.

void spread(size_t index, size_t nbytes);
At offset index into buffer, create nbytes of space by shifting upwards all data past index.

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.parallelism

std.parallelism implements high-level primitives for SMP parallelism. These include parallel foreach, parallel reduce, parallel eager map, pipelining and future/promise parallelism. 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 std.concurrency.

std.parallelism is based on the concept of a Task. A Task is an object that represents the fundamental unit of work in this library and may be executed in parallel with any other Task. Using 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 Task. They automatically create one or more Task objects, or closely related types that are conceptually identical but not part of the public API.

After creation, a Task may be executed in a new thread, or submitted to a TaskPool for execution. A TaskPool encapsulates a task queue and its worker threads. Its purpose is to efficiently map a large number of Tasks onto a smaller number of threads. A task queue is a FIFO queue of Task objects that have been submitted to the TaskPool and are awaiting execution. A worker thread is a thread that is associated with exactly one task queue. It executes the 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 Task is needed before execution by a worker thread has begun, the Task can be removed from the task queue and executed immediately in the thread where the result is needed.

Warning:
Unless marked as @trusted or @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:
std/parallelism.d

Author:
David Simcha

License:
Boost License 1.0

struct Task(alias fun, Args...);
Task represents the fundamental unit of work. A Task may be executed in parallel with any other 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 workForce, yieldForce, or spinForce is used to ensure that the Task has finished executing and to obtain the return value, if any. These functions and done also act as full memory barriers, meaning that any memory writes made in the thread that executed the Task are guaranteed to be visible in the calling thread after one of these functions returns.

The std.parallelism.task and std.parallelism.scopedTask functions can be used to create an instance of this struct. See task for usage examples.

Function results are returned from yieldForce, spinForce and workForce by ref. If fun returns by ref, the reference will point to the returned reference of 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 ref and out arguments are not propagated to the call site, only to args in this struct.

alias _args[1 .. __dollar] args;
The arguments the function was called with. Changes to out and ref arguments will be visible here.

alias typeof(fun(_args)) ReturnType;
The return type of the function called by this Task. This can be void.

@trusted ReturnType spinForce();
If the 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 Task to be available on a timescale shorter than that of an OS context switch.

@trusted ReturnType yieldForce();
If the 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.

@trusted ReturnType workForce();
If this 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 Task from the TaskPool instance that this 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 Task was executed using executeInNewThread, wait on a condition variable.

@trusted bool done();
Returns true if the Task is finished executing.

Throws:
Rethrows any exception thrown during the execution of the Task.

@trusted void executeInNewThread();
@trusted void executeInNewThread(int priority);
Create a new thread for executing this 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 Task. If one is provided, its value is forwarded to core.thread.Thread.priority. See std.parallelism.task for usage example.

auto task(alias fun, Args...)(Args args);
Creates a Task on the GC heap that calls an alias. This may be executed via Task.executeInNewThread or by submitting to a std.parallelism.TaskPool. A globally accessible instance of TaskPool is provided by std.parallelism.taskPool.

Returns:
A pointer to the Task.

Examples:
// 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(F, Args...)(F delegateOrFp, Args args);
Creates a Task on the GC heap that calls a function pointer, delegate, or class/struct with overloaded opCall.

Examples:
// 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 scopedTask, which takes a scope delegate.

@trusted auto task(F, Args...)(F fun, Args args);
Version of task usable from @safe code. Usage mechanics are identical to the non-@safe case, but safety introduces some restrictions:

1. fun must be @safe or @trusted.

2. F must not have any unshared aliasing as defined by std.traits.hasUnsharedAliasing. This means it may not be an unshared delegate or a non-shared class or struct with overloaded opCall. This also precludes accepting template alias parameters.

3. Args must not have unshared aliasing.

4. fun must not return by reference.

5. The return type must not have unshared aliasing unless fun is pure or the Task is executed via executeInNewThread instead of using a TaskPool.

auto scopedTask(alias fun, Args...)(Args args);
auto scopedTask(F, Args...)(scope F delegateOrFp, Args args);
@trusted auto scopedTask(F, Args...)(F fun, Args args);
These functions allow the creation of Task objects on the stack rather than the GC heap. The lifetime of a Task created by scopedTask cannot exceed the lifetime of the scope it was created in.

scopedTask might be preferred over task:

1. When a 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 scopedTask takes a scope delegate.

2. As a micro-optimization, to avoid the heap allocation associated with task or with the creation of a closure.

Usage is otherwise identical to task.

Notes:
Task objects created using scopedTask will automatically call Task.yieldForce in their destructor if necessary to ensure the Task is complete before the stack frame they reside on is destroyed.

immutable uint totalCPUs;
The total number of CPU cores available on the current machine, as reported by the operating system.

class TaskPool;
This class encapsulates a task queue and a set of worker threads. Its purpose is to efficiently map a large number of Tasks onto a smaller number of threads. A task queue is a FIFO queue of Task objects that have been submitted to the TaskPool and are awaiting execution. A worker thread is a thread that executes the 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 std.parallelism.taskPool property. Occasionally it is useful to explicitly instantiate a TaskPool:

1. When you want 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.

@trusted this();
Default constructor that initializes a TaskPool with 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 TaskPool operate transparently in single-threaded mode.

@trusted this(size_t nWorkers);
Allows for custom number of worker threads.

ParallelForeach!(R) parallel(R)(R range, size_t workUnitSize);
ParallelForeach!(R) parallel(R)(R range);
Implements a parallel foreach loop over a range. This works by implicitly creating and submitting one Task to the TaskPool for each worker thread. A work unit is a set of consecutive elements of 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 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 workUnitSize should be. For very expensive loop bodies, workUnitSize should be 1. An overload that chooses a default work unit size is also available.

Examples:
    // 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 range.length.

Breaking from a parallel foreach loop via a break, labeled break, labeled continue, return or goto statement throws a ParallelForeachError.

In the case of non-random access ranges, parallel foreach buffers lazily to an array of size workUnitSize before executing the parallel portion of the loop. The exception is that, if a parallel foreach is executed over a range returned by asyncBuf or map, the copying is elided and the buffers are simply swapped. In this case workUnitSize is ignored and the work unit size is set to the buffer size of 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.

Exception Handling:

When at least one exception is thrown from inside a parallel foreach loop, the submission of additional 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 Throwable.next and rethrown. The order of the exception chaining is non-deterministic.

template amap(functions...)
Eager parallel map. The eagerness of this function means it has less overhead than the lazily evaluated TaskPool.map and should be preferred where the memory requirements of eagerness are acceptable. functions are the functions to be evaluated, passed as template alias parameters in a style similar to std.algorithm.map. The first argument must be a random access range.

    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 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 amap.

Exception Handling:

When at least one exception is thrown from inside the map functions, the submission of additional 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 Throwable.next and rethrown. The order of the exception chaining is non-deterministic.

auto amap(Args...)(Args args);

template map(functions...)
A semi-lazy parallel map that can be used for pipelining. The map functions are evaluated for the first bufSize elements and stored in a buffer and made available to 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.

map has more overhead than the simpler procedure used by amap but avoids the need to keep all results in memory simultaneously and works with non-random access ranges.

Parameters:
source | The input range to be mapped. If source is not random access it will be lazily buffered to an array of size 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 Task. Must be less than or equal to bufSize, and should be a fraction of 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 source has a length.

Notes:
If a range returned by map or asyncBuf is used as an input to 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 map and asyncBuf are non-random access ranges. This means that the bufSize parameter passed to the current call to map will be ignored and the size of the buffer will be the buffer size of source.

Examples:
    // 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;
    }

Exception Handling:

Any exceptions thrown while iterating over source or computing the map function are re-thrown on a call to 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 TaskPool.amap.

auto map(S)(S source, size_t bufSize = 100, size_t workUnitSize = size_t.max);

auto asyncBuf(S)(S source, size_t bufSize = 100);
Given a source range that is expensive to iterate over, returns an input range that asynchronously buffers the contents of source into a buffer of bufSize elements in a worker thread, while making prevously buffered elements from a second buffer, also of size bufSize, available via the range interface of the returned object. The returned range has a length iff hasLength!(S). asyncBuf is useful, for example, when performing expensive operations on the elements of ranges that represent data on a disk or network.

Examples:
    import std.conv, std.stdio;

    void main()
    {
        // Fetch lines of a file in a background thread
        // while processing prevously 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);
        }
    }

Exception Handling:

Any exceptions thrown while iterating over source are re-thrown on a call to popFront or, if thrown during construction, simply allowed to propagate to the caller.

auto asyncBuf(C1, C2)(C1 next, C2 empty, size_t initialBufSize = 0, size_t nBuffers = 100);
Given a callable object next that writes to a user-provided buffer and a second callable object empty that determines whether more data is available to write via next, returns an input range that asynchronously calls next with a set of size 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 asyncBuf, the first half of the buffers are made available via the range interface while the second half are filled and vice-versa.

Parameters:
next | A callable object that takes a single argument that must be an array with mutable elements. When called, 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 bool. This is used to signify that no more data is available to be obtained by calling next.
initialBufSize | The initial size of each buffer. If next takes its array by reference, it may resize the buffers.
nBuffers | The number of buffers to cycle through when calling next.

Examples:
    // Fetch lines of a file in a background
    // thread while processing prevously 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);
    }

Exception Handling:

Any exceptions thrown while iterating over range are re-thrown on a call to 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.

template reduce(functions...)
Parallel reduce on a random access range. Except as otherwise noted, usage is similar to std.algorithm.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, functions must be associative. For notational simplicity, let # be an infix operator representing 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 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 std.algorithm.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 std.algorithm.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 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 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));

Exception Handling:

After this function is finished executing, any exceptions thrown are chained together via Throwable.next and rethrown. The chaining order is non-deterministic.

auto reduce(Args...)(Args args);

const nothrow @property @safe size_t workerIndex();
Gets the index of the current thread relative to this 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 this.size.

This function is useful for maintaining worker-local resources.

Examples:
    // 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));
        }
    }

struct WorkerLocalStorage(T);
Struct for creating worker-local storage. Worker-local storage is thread-local storage that exists only for worker threads in a given 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 TaskPool that created it, and one thread outside this 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 WorkerLocalStorageStorage are:

1. Performing parallel reductions with an imperative, as opposed to functional, programming style. In this case, it's useful to treat 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.

Examples:
    // 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;
    }

@property T get();
Get the current thread's instance. Returns by ref. Note that calling get from any thread outside the 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 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.

@property void get(T val);
Assign a value to the current thread's instance. This function has the same caveats as its overload.

@property WorkerLocalStorageRange!(T) toRange();
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 get method again will result in an assertion failure if assertions are enabled.

struct WorkerLocalStorageRange(T);
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 WorkerLocalStorage.toRange. Once instantiated, this object behaves as a finite random-access range with assignable, lvalue elemends and a length equal to the number of worker threads in the TaskPool that created it plus 1.

WorkerLocalStorage!(T) workerLocalStorage(T)(lazy T initialVal = T.init);
Creates an instance of worker-local storage, initialized with a given value. The value is lazy so that you can, for example, easily create one instance of a class for each worker. For usage example, see the WorkerLocalStorage struct.

@trusted void stop();
Signals to all worker threads to terminate as soon as they are finished with their current Task, or immediately if they are not executing a Task. Tasks that were in queue will not be executed unless a call to Task.workForce, Task.yieldForce or Task.spinForce causes them to be executed.

Use only if you have waitied on every Task and therefore know the queue is empty, or if you speculatively executed some tasks and no longer need the results.

@trusted void finish(bool blocking = false);
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 TaskPool is employed as a rudimentary scheduler for tasks which communicate by means other than return values.

Warning:
Calling this function with blocking = true from a worker thread that is a member of the same TaskPool that finish is being called on will result in a deadlock.

const pure nothrow @property @safe size_t size();
Returns the number of worker threads in the pool.

void put(alias fun, Args...)(ref Task!(fun, Args) task);
void put(alias fun, Args...)(Task!(fun, Args)* task);
Put a Task object on the back of the task queue. The 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 Tasks if std.traits.hasUnsharedAliasing is false for the Task's return type or the function the Task executes is pure. Task objects that meet all other requirements specified in the @trusted overloads of task and scopedTask may be created and executed from @safe code via Task.executeInNewThread but not via TaskPool.

While this function takes the address of variables that may be on the stack, some overloads are marked as @trusted. 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 TaskPool.

@property @trusted bool isDaemon();
@property @trusted void isDaemon(bool newVal);
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 TaskPool with non-daemon threads is active, either stop or finish must be called on it before the program can terminate.

The worker treads in the TaskPool instance returned by the 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.

@property @trusted int priority();
@property @trusted void priority(int newPriority);
These functions allow getting and setting the OS scheduling priority of the worker threads in this TaskPool. They forward to core.thread.Thread.priority, so a given priority value here means the same thing as an identical priority value in core.thread.

Note:
For a size zero pool, the getter arbitrarily returns core.thread.Thread.PRIORITY_MIN and the setter has no effect.

@property @trusted TaskPool taskPool();
Returns a lazily initialized global instantiation of 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 TaskPool.stop or TaskPool.finish before terminating the main thread.

@property @trusted uint defaultPoolThreads();
@property @trusted void defaultPoolThreads(uint newVal);
These properties get and set the number of worker threads in the TaskPool instance returned by taskPool. The default value is totalCPUs - 1. Calling the setter after the first call to taskPool does not changes number of worker threads in the instance returned by taskPool.

ParallelForeach!(R) parallel(R)(R range);
ParallelForeach!(R) parallel(R)(R range, size_t workUnitSize);
Convenience functions that forwards to 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);
}

Copyright (c) 2009-2011, David Simcha. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.path

This module is used to manipulate path strings.

All functions, with the exception of expandTilde (and in some cases absolutePath and 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 std.file.isDir and std.file.exists.

Note that on Windows, both the backslash ('\') and the slash ('/') are in principle valid directory separators. This module treats them both on equal footing, but in cases where a new separator is added, a backslash will be used. Furthermore, the 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 isValidFilename and 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.

Authors:
Lars Tandle Kyllingstad, Walter Bright, Grzegorz Adam Hankiewicz, Thomas Kühne, Andrei Alexandrescu

License:
Boost License 1.0

Source:
std/path.d

string dirSeparator;
String used to separate directory names in a path. Under POSIX this is a slash, under Windows a backslash.

string pathSeparator;
Path separator string. A colon under POSIX, a semicolon under Windows.

pure nothrow @safe bool isDirSeparator(dchar c);
Determines whether the given character is a directory separator.

On Windows, this includes both '\' and '/'. On POSIX, it's just '/'.

enum CaseSensitive;
This enum is used as a template argument to functions which compare file names, and determines whether the comparison is case sensitive or not.

no
File names are case insensitive

yes
File names are case sensitive

osDefault
The default (or most common) setting for the current platform. That is, no on Windows and Mac OS X, and yes on all POSIX systems except OS X (Linux, *BSD, etc.).

pure @trusted inout(C)[] baseName(C)(inout(C)[] path);
pure @safe inout(C)[] baseName(CaseSensitive cs = CaseSensitive.osDefault, C, C1)(inout(C)[] path, in C1[] suffix);
Returns the name of a file, without any leading directory and with an optional suffix chopped off.

If suffix is specified, it will be compared to path using filenameCmp!cs, where cs is an optional template parameter determining whether the comparison is case sensitive or not. See the filenameCmp documentation for details.

Examples:
    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 only strips away the specified suffix, which doesn't necessarily have to represent an extension. If you want to remove the extension from a path, regardless of what the extension is, use stripExtension. If you want 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 the POSIX requirements for the 'basename' shell utility (with suitable adaptations for Windows paths).

C[] dirName(C)(C[] path);
Returns the directory part of a path. On Windows, this includes the drive letter if present.

This function performs a memory allocation if and only if path is mutable and does not have a directory (in which case a new mutable string is needed to hold the returned current-directory symbol, ".").

Examples:
    assert (dirName("file")        == ".");
    assert (dirName("dir/file")    == "dir");
    assert (dirName("/file")       == "/");
    assert (dirName("dir/subdir/") == "dir");

    version (Windows)
    {
        assert (dirName("d:file")      == "d:");
        assert (dirName(`d:\dir\file`) == `d:\dir`);
        assert (dirName(`d:\file`)     == `d:\`);
        assert (dirName(`dir\subdir\`) == `dir`);
    }

Standards:
This function complies with the POSIX requirements for the 'dirname' shell utility (with suitable adaptations for Windows paths).

pure nothrow @safe inout(C)[] rootName(C)(inout(C)[] path);
Returns the root directory of the specified path, or null if the path is not rooted.

Examples:
    assert (rootName("foo") is null);
    assert (rootName("/foo") == "/");

    version (Windows)
    {
        assert (rootName(`\foo`) == `\`);
        assert (rootName(`c:\foo`) == `c:\`);
        assert (rootName(`\\server\share\foo`) == `\\server\share`);
    }

pure nothrow @safe inout(C)[] driveName(C)(inout(C)[] path);
Returns the drive of a path, or null if the drive is not specified. In the case of UNC paths, the network share is returned.

Always returns null on POSIX.

Examples:
    version (Windows)
    {
        assert (driveName(`d:\file`) == "d:");
        assert (driveName(`\\server\share\file`) == `\\server\share`);
        assert (driveName(`dir\file`).empty);
    }

pure nothrow @safe inout(C)[] stripDrive(C)(inout(C)[] path);
Strips the drive from a Windows path. On POSIX, the path is returned unaltered.

Example:
    version (Windows)
    {
        assert (stripDrive(`d:\dir\file`) == `\dir\file`);
        assert (stripDrive(`\\server\share\dir\file`) == `\dir\file`);
    }

pure nothrow @safe inout(C)[] extension(C)(inout(C)[] path);
Returns the extension part of a file name, including the dot.

If there is no extension, null is returned.

Examples:
    assert (extension("file").empty);
    assert (extension("file.ext")       == ".ext");
    assert (extension("file.ext1.ext2") == ".ext2");
    assert (extension("file.")          == ".");
    assert (extension(".file").empty);
    assert (extension(".file.ext")      == ".ext");

pure nothrow @safe inout(C)[] stripExtension(C)(inout(C)[] path);
Returns the path with the extension stripped off.

Examples:
    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");

pure nothrow @trusted immutable(Unqual!(C1))[] setExtension(C1, C2)(in C1[] path, in C2[] ext);
pure nothrow @trusted immutable(C1)[] setExtension(C1, C2)(immutable(C1)[] path, const(C2)[] ext);
Returns a string containing the path given by path, but where the extension has been set to 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 ext is optional.

This function normally allocates a new string (the possible exception being the case when path is immutable and doesn't already have an extension).

Examples:
    assert (setExtension("file", "ext")      == "file.ext");
    assert (setExtension("file", ".ext")     == "file.ext");
    assert (setExtension("file.old", "new")  == "file.new");
    assert (setExtension("file.old", ".new") == "file.new");

pure @trusted immutable(Unqual!(C1))[] defaultExtension(C1, C2)(in C1[] path, in C2[] ext);
Returns the path given by path, with the extension given by 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.

Examples:
    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");

pure @safe immutable(C)[] buildPath(C)(const(C[])[] paths...);
Combines one or more path components.

The given path components are concatenated with each other, and if necessary, directory separators are inserted between them. If any of the path components are rooted (as defined by isRooted) the preceding path components will be dropped.

This function always allocates memory to hold the resulting path.

Examples:
    version (Posix)
    {
        assert (buildPath("foo", "bar", "baz") == "foo/bar/baz");
        assert (buildPath("/foo/", "bar")      == "/foo/bar");
        assert (buildPath("/foo", "/bar")      == "/bar");
    }

    version (Windows)
    {
        assert (buildPath("foo", "bar", "baz") == `foo\bar\baz`);
        assert (buildPath(`c:\foo`, "bar")    == `c:\foo\bar`);
        assert (buildPath("foo", `d:\bar`)    == `d:\bar`);
        assert (buildPath("foo", `\bar`)      == `\bar`);
    }

pure nothrow @trusted immutable(C)[] buildNormalizedPath(C)(const(C[])[] paths...);
Performs the same task as buildPath, while at the same time resolving current/parent directory symbols ("." and "..") and removing superfluous directory separators. On Windows, slashes are replaced with backslashes.

Note that this function does not resolve symbolic links.

This function always allocates memory to hold the resulting path.

Examples:
    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`);
    }

pure nothrow @safe auto pathSplitter(C)(const(C)[] path);
Returns a bidirectional range that iterates over the elements of a path.

Examples:
    assert (equal(pathSplitter("/"), ["/"]));
    assert (equal(pathSplitter("/foo/bar"), ["/", "foo", "bar"]));
    assert (equal(pathSplitter("//foo/bar"), ["//foo", "bar"]));
    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"]));
    }

pure nothrow @safe bool isRooted(C)(in C[] path);
Determines 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"));
    }

pure nothrow @safe bool isAbsolute(C)(in C[] path);
Determines whether a path is absolute or not.

Examples:
On POSIX, an absolute path starts at the root directory. (In fact, isAbsolute is just an alias for 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:\" or "d:/", where 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"));
    }

pure @safe string absolutePath(string path, lazy string base = getcwd());
Translates path into an absolute path.

The following algorithm is used:
  1. If path is empty, return null.
  2. If path is already absolute, return it.
  3. Otherwise, append path to base and return the result. If 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.

Examples:
    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`);
    }

Throws:
Exception if the specified base directory is not absolute.

string relativePath(CaseSensitive cs = CaseSensitive.osDefault)(string path, lazy string base = getcwd());
Translates path into a relative path.

The returned path is relative to base, which is by default taken to be the current working directory. If specified, 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:
  1. If path is a relative directory, return it unaltered.
  2. Find a common root between path and base. If there is no common root, return path unaltered.
  3. Prepare a string with as many "../" or "..\" as necessary to reach the common root from base path.
  4. 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 filenameCmp documentation for details.

The function allocates memory if and only if it reaches the third stage of the above algorithm.

Examples:
    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`);
    }

Throws:
Exception if the specified base directory is not absolute.

pure nothrow @safe int filenameCharCmp(CaseSensitive cs = CaseSensitive.osDefault)(dchar a, dchar b);
Compares filename characters and return < 0 if a < b, 0 if a == b and > 0 if a > b.

This function can perform a case-sensitive or a case-insensitive comparison. This is controlled through the cs template parameter which, if not specified, is given by CaseSensitive .osDefault.

On Windows, the backslash and slash characters ('\' and '/') are considered equal.

Examples:
    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);
    }

pure @safe int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, C1, C2)(const(C1)[] filename1, const(C2)[] filename2);
Compares file names and returns < 0 if filename1 < filename2, 0 if filename1 == filename2 and > 0 if filename1 > filename2.

Individual characters are compared using filenameCharCmp!cs, where cs is an optional template parameter determining whether the comparison is case sensitive or not. See the filenameCharCmp documentation for details.

Examples:
    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);
    }

pure nothrow @safe bool globMatch(CaseSensitive cs = CaseSensitive.osDefault, C)(const(C)[] path, const(C)[] pattern);
Matches a pattern against a path.

Some characters of pattern have a special meaning (they are meta-characters) and can't be escaped. These are:

* Matches 0 or more instances of any character.
? Matches exactly one instance of any character.
[chars] | Matches one instance of any character that appears between the brackets.
[!chars] | Matches one instance of any character that does not appear between the brackets after the exclamation mark.
{string1,string2,…} | Matches either of the specified strings.

Individual characters are compared using filenameCharCmp!cs, where cs is an optional template parameter determining whether the comparison is case sensitive or not. See the filenameCharCmp documentation for details.

Note that directory separators and dots don't stop a meta-character from matching further portions of the path.

Returns:
true if pattern matches path, false otherwise.

See Also:
Wikipedia: glob (programming)

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

pure nothrow @safe bool isValidFilename(C)(in C[] filename);
Checks that the given file or directory name is valid.

This function returns true if and only if filename is not empty, not too long, and does not contain invalid characters.

The maximum length of filename is given by the constant 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 filename is a string of wchars.)

On Windows, the following criteria must be satisfied (source):
  • filename must not contain any characters whose integer representation is in the range 0-31.
  • filename must not contain any of the following reserved characters: <>:"/\|?*
  • filename may not end with a space (' ') or a period ('.').

On POSIX, filename may not contain a forward slash ('/') or the null character ('\0').

pure nothrow @safe bool isValidPath(C)(in C[] path);
Checks whether path is a valid path.

Generally, this function checks that path is not empty, and that each component of the path either satisfies isValidFilename or is equal to "." or "..". It does not check whether the path points to an existing file or directory; use std.file.exists for this purpose.

On Windows, some special rules apply:
  • If the second character of path is a colon (':'), the first character is interpreted as a drive letter, and must be in the range A-Z (case insensitive).
  • If path is on the form `\\server\share\...` (UNC path), isValidFilename is applied to server and share as well.
  • If path starts with `\\?\` (long UNC path), the only requirement for the rest of the string is that it does not contain the null character.
  • If path starts with `\\.\` (Win32 device namespace) this function returns false; such paths are beyond the scope of this module.

string expandTilde(string inputPath);
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 HOME. The second way is putting a username after the tilde (i.e. ~john/Mail). Here, the username will be searched for in the user database (i.e. /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 ~user syntax may give different values from just ~ 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.

Returns:
inputPath with the tilde expanded, or just inputPath if it could not be expanded. For Windows, expandTilde merely returns its argument inputPath.

Examples:
    void processFile(string path)
    {
        // Allow calling this function with paths such as ~/foo
        auto fullPath = expandTilde(path);
        ...
    }

int fcmp(alias pred = "a < b", S1, S2)(S1 s1, S2 s2);
Deprecated. It will be removed in October 2012. Please use filenameCmp instead.

Compare file names.

Returns:
< 0 | filename1 < filename2
= 0 | filename1 == filename2
> 0 | filename1 > filename2

string getExt()(string fullname);
Deprecated. It will be removed in October 2012. Please use extension instead.

Extracts the extension from a filename or path.

This function will search fullname from the end until the first dot, path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a dot was found, characters to its right are returned. If a path separator was found, or fullname didn't contain any dots or path separators, returns null.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getExt(r"d:\path\foo.bat") // "bat"
     getExt(r"d:\path.two\bar") // null
 }
 version(Posix)
 {
     getExt(r"/home/user.name/bar.")  // ""
     getExt(r"d:\\path.two\\bar")     // r"two\\bar"
     getExt(r"/home/user/.resource")  // "resource"
 }

string getName()(string fullname);
Deprecated. It will be removed in October 2012. Please use stripExtension instead.

Returns the extensionless version of a filename or path.

This function will search fullname from the end until the first dot, path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a dot was found, characters to its left are returned. If a path separator was found, or fullname didn't contain any dots or path separators, returns null.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getName(r"d:\path\foo.bat") => r"d:\path\foo"
     getName(r"d:\path.two\bar") => null
 }
 version(Posix)
 {
     getName("/home/user.name/bar.")  => "/home/user.name/bar"
     getName(r"d:\path.two\bar") => r"d:\path"
     getName("/home/user/.resource") => "/home/user/"
 }

Char[] basename(Char, ExtChar = immutable(char))(Char[] fullname, ExtChar[] extension = null);
Deprecated. It will be removed in October 2012. Please use baseName instead.

Extracts the base name of a path and optionally chops off a specific suffix.

This function will search fullname from the end until the first path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search. After the search has ended, keep the portion to the right of the separator if found, or the entire fullname otherwise. If the kept portion has suffix extension, remove that suffix. Return the remaining string.

Returns:
The portion of fullname left after the path part and the extension part, if any, have been removed.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     basename(r"d:\path\foo.bat") => "foo.bat"
     basename(r"d:\path\foo", ".bat") => "foo"
 }
 version(Posix)
 {
     basename("/home/user.name/bar.")  => "bar."
     basename("/home/user.name/bar.", ".")  => "bar"
 }

Char[] dirname(Char)(Char[] fullname);
Deprecated. It will be removed in October 2012. Please use dirName instead.

Extracts the directory part of a path.

This function will search fullname from the end until the first path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a path separator was found, all the characters to its left without any trailing path separators are returned. Otherwise, "." is returned.

The found path separator will be included in the returned string if and only if it represents the root.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     assert(dirname(r"d:\path\foo.bat") == r"d:\path");
     assert(dirname(r"d:\path") == r"d:\");
     assert(dirname("d:foo.bat") == "d:.");
     assert(dirname("foo.bat") == ".");
 }
 version(Posix)
 {
     assert(dirname("/home/user") == "/home");
     assert(dirname("/home") == "/");
     assert(dirname("user") == ".");
 }

Char[] getDrive(Char)(Char[] fullname);
Deprecated. It will be removed in October 2012. Please use driveName instead.

Extracts the drive letter of a path.

This function will search fullname for a colon from the beginning.

Returns:
If a colon is found, all the characters to its left plus the colon are returned. Otherwise, null is returned.

Under Linux, this function always returns null immediately.

Throws:
Nothing.

Examples:
 getDrive(r"d:\path\foo.bat") => "d:"

string defaultExt()(string filename, string ext);
Deprecated. It will be removed in October 2012. Please use defaultExtension instead.

Appends a default extension to a filename.

This function first searches filename for an extension and appends ext if there is none. ext should not have any leading dots, one will be inserted between filename and ext if filename doesn't already end with one.

Returns:
filename if it contains an extension, otherwise filename + ext.

Throws:
Nothing.

Examples:
 defaultExt("foo.txt", "raw") => "foo.txt"
 defaultExt("foo.", "raw") => "foo.raw"
 defaultExt("bar", "raw") => "bar.raw"

string addExt()(string filename, string ext);
Deprecated. It will be removed in October 2012. Please use setExtension instead.

Adds or replaces an extension to a filename.

This function first searches filename for an extension and replaces it with ext if found. If there is no extension, ext will be appended. ext should not have any leading dots, one will be inserted between filename and ext if filename doesn't already end with one.

Returns:
filename + ext if filename is extensionless. Otherwise strips filename's extension off, appends ext and returns the result.

Throws:
Nothing.

Examples:
 addExt("foo.txt", "raw") => "foo.raw"
 addExt("foo.", "raw") => "foo.raw"
 addExt("bar", "raw") => "bar.raw"

bool isabs()(in char[] path);
Deprecated. It will be removed in October 2012. Please use isAbsolute instead.

Checks if path is absolute.

Returns:
non-zero if the path starts from the root directory (Linux) or drive letter and root directory (Windows), zero otherwise.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     isabs(r"relative\path") => 0
     isabs(r"\relative\path") => 0
     isabs(r"d:\absolute") => 1
 }
 version(Posix)
 {
     isabs("/home/user") => 1
     isabs("foo") => 0
 }

string rel2abs()(string path);
Deprecated. It will be removed in October 2012. Please use absolutePath instead.

Converts a relative path into an absolute path.

string join()(const(char)[] p1, const(char)[] p2, const(char[])[] more...);
Deprecated. It will be removed in October 2012. Please use buildPath instead.

Joins two or more path components.

If p1 doesn't have a trailing path separator, one will be appended to it before concatenating p2.

Returns:
p1 ~ p2. However, if p2 is an absolute path, only p2 will be returned.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     join(r"c:\foo", "bar") => r"c:\foo\bar"
     join("foo", r"d:\bar") => r"d:\bar"
 }
 version(Posix)
 {
     join("/foo/", "bar") => "/foo/bar"
     join("/foo", "/bar") => "/bar"
 }

bool fncharmatch()(dchar c1, dchar c2);
Deprecated. It will be removed in October 2012. Please use filenameCharCmp instead.

Matches filename characters.

Under Windows, the comparison is done ignoring case. Under Linux an exact match is performed.

Returns:
non zero if c1 matches c2, zero otherwise.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     fncharmatch('a', 'b') => 0
     fncharmatch('A', 'a') => 1
 }
 version(Posix)
 {
     fncharmatch('a', 'b') => 0
     fncharmatch('A', 'a') => 0
 }

bool fnmatch()(const(char)[] filename, const(char)[] pattern);
Deprecated. It will be removed in October 2012. Please use globMatch instead.

Matches a pattern against a filename.

Some characters of pattern have special a meaning (they are meta-characters) and can't be escaped. These are:

* Matches 0 or more instances of any character.
? Matches exactly one instances of any character.
[chars] | Matches one instance of any character that appears between the brackets.
[!chars] | Matches one instance of any character that does not appear between the brackets after the exclamation mark.

Internally individual character comparisons are done calling fncharmatch(), so its rules apply here too. Note that path separators and dots don't stop a meta-character from matching further portions of the filename.

Returns:
non zero if pattern matches filename, zero otherwise.

See Also:
fncharmatch().

Throws:
Nothing.

Examples:
 version(Windows)
 {
     fnmatch("foo.bar", "*") => 1
     fnmatch(r"foo/foo\bar", "f*b*r") => 1
     fnmatch("foo.bar", "f?bar") => 0
     fnmatch("Goo.bar", "[fg]???bar") => 1
     fnmatch(r"d:\foo\bar", "d*foo?bar") => 1
 }
 version(Posix)
 {
     fnmatch("Go*.bar", "[fg]???bar") => 0
     fnmatch("/foo*home/bar", "?foo*bar") => 1
     fnmatch("foobar", "foo?bar") => 1
 }

Copyright (c) 2000–2011, the authors. All rights reserved. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.process

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Vladimir Panteleev

Source:
std/process.d

int system(string command);
Execute command in a command shell.

Returns:
If command is null, returns nonzero if the command interpreter is found, and zero otherwise. If command is not null, returns -1 on error, or the exit status of command (which may in turn signal an error in command's execution).

Note:
On Unix systems, the homonym C function (which is accessible to D programs as std.c.system) returns a code in the same format as waitpid, waitpid, meaning that C programs must use the WEXITSTATUS macro to extract the actual exit code from the system call. D's system automatically extracts the exit status.

int execv(in string pathname, in string[] argv);
int execve(in string pathname, in string[] argv, in string[] envp);
int execvp(in string pathname, in string[] argv);
int execvpe(in string pathname, in string[] argv, in string[] envp);
Replace the current process by executing a command, pathname, with the arguments in argv. Typically, the first element of argv is the command being executed, i.e. argv[0] == pathname. The 'p' versions of exec search the PATH environment variable for 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.

alias core.sys.windows.windows.GetCurrentProcessId getpid;
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());

string shell(string cmd);
Runs cmd in a shell and returns its standard output. If the process could not be started or exits with an error code, throws an exception.

Example:
   auto tempFilename = chomp(shell("mcookie"));
   auto f = enforce(fopen(tempFilename), "w");
   scope(exit)
   {
       fclose(f) == 0 || assert(false);
       system(escapeShellCommand("rm", tempFilename));
   }
   ... use f ...

string getenv(in char[] name);
Gets the value of environment variable name as a string. Calls std.c.stdlib.getenv internally.

void setenv(in char[] name, in char[] value, bool overwrite);
Sets the value of environment variable name to value. If the value was written, or the variable was already present and overwrite is false, returns normally. Otherwise, it throws an exception. Calls std.c.stdlib.setenv internally.

void unsetenv(in char[] name);
Removes variable name from the environment. Calls std.c.stdlib.unsetenv internally.

alias Environment environment;
Manipulates environment variables using an associative-array-like interface.

Examples:
    // Return variable, or throw an exception if it doesn't exist.
    auto path = environment["PATH"];

    // Add/replace variable.
    environment["foo"] = "bar";

    // Remove variable.
    environment.remove("foo");

    // Return variable, or null if it doesn't exist.
    auto foo = environment.get("foo");

    // Return variable, or a default value if it doesn't exist.
    auto foo = environment.get("foo", "default foo value");

    // Return an associative array of type string[string] containing
    // all the environment variables.
    auto aa = environment.toAA();

void browse(string url);
Start up the browser and set it to viewing the page at url.

pure nothrow string escapeWindowsArgument(in char[] arg);
Quote an argument in a manner conforming to the behavior of CommandLineToArgvW.

string escapeShellCommand(in char[][] args...);
Escape an argv-style argument array to be used with the system or shell functions.

Example:
string url = "http://dlang.org/";
system(escapeShellCommand("wget", url, "-O", "dlang-index.html"));

Concatenate multiple escapeShellCommand and escapeShellFileName results to use shell redirection or piping operators.

Example:
system(
    escapeShellCommand("curl", "http://dlang.org/download.html") ~
    "|" ~
    escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
    ">" ~
    escapeShellFileName("D download links.txt"));

pure nothrow string escapeShellFileName(in char[] fn);
Escape a filename to be used for shell redirection with the system or shell functions.

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.random

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 Mt19937 generator, which derives its name from "Mersenne Twister with a period of 2 to the power of 19937". In memory-constrained situations, linear congruential generators such as MinstdRand0 and MinstdRand might be useful. The standard library provides an alias 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.

Source:
std/random.d

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu Masahiro Nakagawa (Xorshift randome generator) Joseph Rushton Wakeling (Algorithm D for random sampling)

Credits:
The entire random number library architecture is derived from the excellent C++0X random number facility proposed by Jens Maurer and contributed to by researchers at the Fermi laboratory(excluding Xorshift).

template isUniformRNG(Rng, ElementType)
template isUniformRNG(Rng)
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:
  • it's an InputRange
  • it has a 'bool isUniformRandom' field readable in CTFE

template isSeedable(Rng, SeedType)
template isSeedable(Rng)
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:
  • it has a 'seed(ElementType)' function

struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m) if (isUnsigned!(UIntType));
Linear Congruential generator.

bool isUniformRandom;
Mark this as a Rng

bool hasFixedRange;
Does this generator have a fixed range? (true).

UIntType min;
Lowest generated value (1 if c == 0, 0 otherwise).

UIntType max;
Highest generated value (modulus - 1).

UIntType multiplier;
UIntType increment;
UIntType modulus;
The parameters of this distribution. The random number is x = (x * multipler + increment) % modulus.

this(UIntType x0);
Constructs a LinearCongruentialEngine generator seeded with x0.

void seed(UIntType x0 = 1);
(Re)seeds the generator.

void popFront();
Advances the random sequence.

UIntType front();
Returns the current number in the random sequence.

typeof(this) save();

bool empty;
Always false (random generators are infinite ranges).

const bool opEquals(ref const LinearCongruentialEngine rhs);
Compares against rhs for equality.

alias LinearCongruentialEngine!(uint, 16807, 0, 2147483647).LinearCongruentialEngine MinstdRand0;
alias LinearCongruentialEngine!(uint, 48271, 0, 2147483647).LinearCongruentialEngine MinstdRand;
Define LinearCongruentialEngine generators with well-chosen parameters. MinstdRand0 implements Park and Miller's "minimal standard" generator that uses 16807 for the multiplier. MinstdRand implements a variant that has slightly better spectral behavior by using the multiplier 48271. Both generators are rather simplistic.

Example:
// 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

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));
The Mersenne Twister generator.

bool isUniformRandom;
Mark this as a Rng

size_t wordSize;
Parameter for the generator.

UIntType min;
Smallest generated value (0).

UIntType max;
Largest generated value.

UIntType defaultSeed;
The default seed value.

this(UIntType value);
Constructs a MersenneTwisterEngine object.

void seed()(UIntType value = defaultSeed);
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(T)(T range);
Seeds a MersenneTwisterEngine object using an InputRange.

Throws:
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.

Examples:
   Mt19937 gen;
   gen.seed(map!((a) => unpredictableSeed)(repeat(0)));

void popFront();
Advances the generator.

UIntType front();
Returns the current random value.

typeof(this) save();

bool empty;
Always false.

alias MersenneTwisterEngine!(uint, 32, 624, 397, 31, 2567483615u, 11, 7, 2636928640u, 15, 4022730752u, 18).MersenneTwisterEngine Mt19937;
A MersenneTwisterEngine instantiated with the parameters of the original engine 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 LinearCongruentialEngine would be the generator of choice.

Example:
// 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

struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType c) if (isUnsigned!(UIntType));
Xorshift generator using 32bit algorithm.

Implemented according to Xorshift RNGs.

bits | period
32 | 2^32 - 1
64 | 2^64 - 1
96 | 2^96 - 1
128 | 2^128 - 1
160 | 2^160 - 1
192 | 2^192 - 2^32

bool isUniformRandom;
Mark this as a Rng

UIntType min;
Smallest generated value.

UIntType max;
Largest generated value.

this(UIntType x0);
Constructs a XorshiftEngine generator seeded with x0.

void seed(UIntType x0);
(Re)seeds the generator.

UIntType front();
Returns the current number in the random sequence.

void popFront();
Advances the random sequence.

typeof(this) save();
Captures a range state.

const bool opEquals(ref const XorshiftEngine rhs);
Compares against rhs for equality.

alias XorshiftEngine!(uint, 32, 13, 17, 5).XorshiftEngine Xorshift32;
alias XorshiftEngine!(uint, 64, 10, 13, 10).XorshiftEngine Xorshift64;
alias XorshiftEngine!(uint, 96, 10, 5, 26).XorshiftEngine Xorshift96;
alias XorshiftEngine!(uint, 128, 11, 8, 19).XorshiftEngine Xorshift128;
alias XorshiftEngine!(uint, 160, 2, 1, 4).XorshiftEngine Xorshift160;
alias XorshiftEngine!(uint, 192, 2, 1, 4).XorshiftEngine Xorshift192;
alias XorshiftEngine!(uint, 128, 11, 8, 19).XorshiftEngine Xorshift;
Define XorshiftEngine generators with well-chosen parameters. See each bits examples of "Xorshift RNGs". Xorshift is a Xorshift128's alias because 128bits implementation is mostly used.

Example:
 // 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 runs

@property uint unpredictableSeed();
A "good" seed for initializing random number engines. Initializing with unpredictableSeed makes engines generate different random number sequences every run.

Example:
auto rnd = Random(unpredictableSeed);
auto n = rnd.front;
...

alias MersenneTwisterEngine!(uint, 32, 624, 397, 31, 2567483615u, 11, 7, 2636928640u, 15, 4022730752u, 18).MersenneTwisterEngine Random;
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.

@property ref Random rndGen();
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.

auto uniform(string boundaries = "[)", T1, T2)(T1 a, T2 b);
auto uniform(string boundaries = "[)", T1, T2, UniformRandomNumberGenerator)(T1 a, T2 b, ref UniformRandomNumberGenerator urng);
Generates a number between a and b. The boundaries parameter controls the shape of the interval (open vs. closed on either side). Valid values for boundaries are "[]", "(]", "[)", and "()". The default interval is closed to the left and open to the right. The version that does not take urng uses the default generator rndGen.

Example:
Random gen(unpredictableSeed);
// Generate an integer in [0, 1023]
auto a = uniform(0, 1024, gen);
// Generate a float in [0, 1)
auto a = uniform(0.0f, 1.0f, gen);

auto uniform(T, UniformRandomNumberGenerator)(ref UniformRandomNumberGenerator urng);
auto uniform(T)();
Generates a uniformly-distributed number in the range [T.min, T.max] for any integral type T. If no random number generator is passed, uses the default rndGen.

F[] uniformDistribution(F = double)(size_t n, F[] useThis = null);
Generates a uniform probability distribution of size n, i.e., an array of size n of positive numbers of type F that sum to 1. If useThis is provided, it is used as storage.

void randomShuffle(Range, RandomGen = Random)(Range r, ref RandomGen gen = rndGen);
Shuffles elements of r using gen as a shuffler. r must be a random-access range with length.

void partialShuffle(Range, RandomGen = Random)(Range r, size_t n, ref RandomGen gen = rndGen);
Partially shuffles the elements of r such that upon returning r[0..n] is a random subset of r and is randomly ordered. r[n..r.length] will contain the elements not in r[0..n]. These will be in an undefined order, but will not be random in the sense that their order after partialShuffle returns will not be independent of their order before partialShuffle was called.

r must be a random-access range with length. n must be less than or equal to r.length.

size_t dice(Rng, Num)(ref Rng rnd, Num[] proportions...);
size_t dice(R, Range)(ref R rnd, Range proportions);
size_t dice(Range)(Range proportions);
size_t dice(Num)(Num[] proportions...);
Rolls a dice with relative probabilities stored in proportions. Returns the index in proportions that was chosen.

Example:
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

struct RandomCover(Range, Random) if (isRandomAccessRange!(Range) && isUniformRNG!(Random));
RandomCover!(Range, Random) randomCover(Range, Random)(Range r, Random rnd);
Covers a given range r in a random manner, i.e. goes through each element of r once and only once, just in a random order. r must be a random-access range with length.

Example:
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ];
auto rnd = Random(unpredictableSeed);
foreach (e; randomCover(a, rnd))
{
    writeln(e);
}

struct RandomSample(R, Random = void) if (isInputRange!(R) && (isUniformRNG!(Random) || is(Random == void)));
auto randomSample(R)(R r, size_t n, size_t total);
auto randomSample(R)(R r, size_t n);
auto randomSample(R, Random)(R r, size_t n, size_t total, Random gen);
auto randomSample(R, Random)(R r, size_t n, Random gen);
Selects a random subsample out of r, containing exactly n elements. The order of elements is the same as in the original range. The total length of r must be known. If total is passed in, the total number of sample is considered to be total. Otherwise, RandomSample uses r.length.

If the number of elements is not exactly total, RandomSample throws an exception. This is because total is essential to computing the probability of selecting elements in the range.

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

RandomSample implements Jeffrey Scott Vitter's Algorithm D (see Vitter 1984, 1987), which selects a sample of size n in O(n) steps and requiring O(n) random variates, regardless of the size of the data being sampled.

const bool empty();
void popFront();
typeof(this) save();
size_t length();
Range primitives.

size_t index();
Returns the index of the visited record.

Copyright Andrei Alexandrescu 2008 - 2009, Joseph Rushton Wakeling 2012. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.range

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 std.algorithm) to be used with a vast variety of different concrete types. For example, a linear search algorithm such as std.algorithm.find works not just for arrays, but for linked-lists, input files, incoming network data, etc.

For more detailed information about the conceptual aspect of ranges and the motivation behind them, see Andrei Alexandrescu's article On Iteration.

This module defines several templates for testing whether a given object is a range, and what kind of range it is:
isInputRange | Tests if something is an input range, defined to be something from which one can sequentially read data using the primitives front, popFront, and empty.
isOutputRange | Tests if something is an output range, defined to be something to which one can sequentially write data using the put primitive.
isForwardRange | Tests if something is a forward range, defined to be an input range with the additional capability that one can save one's current position with the save primitive, thus allowing one to iterate over the same range multiple times.
isBidirectionalRange | Tests if something is a bidirectional range, that is, a forward range that allows reverse traversal using the primitives back and popBack.
isRandomAccessRange | Tests if something is a random access range, which is a bidirectional range that also supports the array subscripting operation via the primitive opIndex.

A number of templates are provided that test for various range capabilities:

hasMobileElements | Tests if a given range's elements can be moved around using the primitives moveFront, moveBack, or moveAt.
ElementType | Returns the element type of a given range.
ElementEncodingType | Returns the encoding element type of a given range.
hasSwappableElements | Tests if a range is a forward range with swappable elements.
hasAssignableElements | Tests if a range is a forward range with mutable elements.
hasLvalueElements | Tests if a range is a forward range with elements that can be passed by reference and have their address taken.
hasLength | Tests if a given range has the length attribute.
isInfinite | Tests if a given range is an infinite range.
hasSlicing | Tests if a given range supports the array slicing operation R[x..y].
walkLength | Computes the length of any range in O(n) time.

A rich set of range creation and composition templates are provided that let you construct new ranges out of existing ranges:

retro | Iterates a bidirectional range backwards.
stride | Iterates a range with stride n.
chain | Concatenates several ranges into a single range.
roundRobin | Given n ranges, creates a new range that return the n first elements of each range, in turn, then the second element of each range, and so on, in a round-robin fashion.
radial | 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.
take | Creates a sub-range consisting of only up to the first n elements of the given range.
takeExactly | Like take, but assumes the given range actually has n elements, and therefore also defines the length property.
takeOne | Creates a random-access range consisting of exactly the first element of the given range.
takeNone | Creates a random-access range consisting of zero elements of the given range.
drop | Creates the range that results from discarding the first n elements from the given range.
dropExactly | Creates the range that results from discarding exactly n of the first elements from the given range.
dropOne | Creates the range that results from discarding the first elements from the given range.
repeat | Creates a range that consists of a single element repeated n times, or an infinite range repeating that element indefinitely.
cycle | Creates an infinite range that repeats the given forward range indefinitely. Good for implementing circular buffers.
zip | Given n ranges, creates a range that successively returns a tuple of all the first elements, a tuple of all the second elements, etc.
lockstep | Iterates n ranges in lockstep, for use in a foreach loop. Similar to zip, except that lockstep is designed especially for foreach loops.
recurrence | Creates a forward range whose values are defined by a mathematical recurrence relation.
sequence | Similar to recurrence, except that a random-access range is created.
iota | Creates a range consisting of numbers between a starting point and ending point, spaced apart by a given interval.
frontTransversal | Creates a range that iterates over the first elements of the given ranges.
transversal | Creates a range that iterates over the n'th elements of the given random-access ranges.
indexed | Creates a range that offers a view of a given range as though its elements were reordered according to a given range of indices.
chunks | Creates a range that returns fixed-size chunks of the original range.

These range-construction tools are implemented using templates; but sometimes an object-based interface for ranges is needed. For this purpose, this module provides a number of object and interface definitions that can be used to wrap around range objects created by the above templates:

InputRange | Wrapper for input ranges.
InputAssignable | Wrapper for input ranges with assignable elements.
ForwardRange | Wrapper for forward ranges.
ForwardAssignable | Wrapper for forward ranges with assignable elements.
BidirectionalRange | Wrapper for bidirectional ranges.
BidirectionalAssignable | Wrapper for bidirectional ranges with assignable elements.
RandomAccessFinite | Wrapper for finite random-access ranges.
RandomAccessAssignable | Wrapper for finite random-access ranges with assignable elements.
RandomAccessInfinite | Wrapper for infinite random-access ranges.
OutputRange | Wrapper for output ranges.
OutputRangeObject | Class that implements the OutputRange interface and wraps the put methods in virtual functions.
InputRangeObject | Class that implements the InputRange interface and wraps the input range methods in virtual functions.

Ranges whose elements are sorted afford better efficiency with certain operations. For this, the assumeSorted function can be used to construct a SortedRange from a pre-sorted range. The std.algorithm.sort function also conveniently returns a SortedRange. SortedRange objects provide some additional range operations that take advantage of the fact that the range is sorted.

Finally, this module also defines some convenience functions for manipulating ranges:

popFrontN | Advances a given range by up to n elements.
popBackN | Advances a given bidirectional range from the right by up to n elements.
popFrontExactly | Advances a given range by up exactly n elements.
popBackExactly | Advances a given bidirectional range from the right by exactly n elements.
moveFront | Removes the front element of a range.
moveBack | Removes the back element of a bidirectional range.
moveAt | Removes the i'th element of a random-access range.

Source:
std/range.d

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to Leonardo Maffi.

template isInputRange(R)
Returns true if R is an input range. An input range must define the primitives empty, popFront, and 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 (r is an object of type R):

  • r.empty returns false iff there is more data available in the range.
  • r.front returns the current element in the range. It may return by value or by reference. Calling r.front is allowed only if calling r.empty has, or would have, returned false.
  • r.popFront advances to the next element in the range. Calling r.popFront is allowed only if calling r.empty has, or would have, returned false.

void put(R, E)(ref R r, E e);
Outputs e to 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.

Code Snippet | Scenario
r.put(e); | R specifically defines a method put accepting an E.
r.put([ e ]); | R specifically defines a method put accepting an E[].
r.front = e; r.popFront(); | R is an input range and e is assignable to r.front.
for (; !e.empty; e.popFront()) put(r, e.front); | Copying range E to range R.
r(e); | R is e.g. a delegate accepting an E.
r([ e ]); | R is e.g. a delegate accepting an E[].

template isOutputRange(R, E)
Returns true if R is an output range for elements of type E. An output range is defined functionally as a range that supports the operation put(r, e) as defined above.

template isForwardRange(R)
Returns true if R is a forward range. A forward range is an input range r that can save "checkpoints" by saving r.save to another value of type R. Notable examples of input ranges that are 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;
R r2 = r1.save; // can save the current position into another range

Saving a range is not duplicating it; in the example above, r1 and 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 save and using it later.

template isBidirectionalRange(R)
Returns true if R is a bidirectional range. A bidirectional range is a forward range that also offers the primitives back and popBack. The following code should compile for any bidirectional range.

R r;
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

The semantics of a bidirectional range (not checkable during compilation) are assumed to be the following (r is an object of type R):

  • r.back returns (possibly a reference to) the last element in the range. Calling r.back is allowed only if calling r.empty has, or would have, returned false.

template isRandomAccessRange(R)
Returns true if R is a random-access range. A random-access range is a bidirectional range that also offers the primitive opIndex, OR an infinite forward range that offers opIndex. In either case, the range must either offer length or be infinite. The following code should compile for any random-access range.

// range is finite and bidirectional or infinite and forward.
static assert(isBidirectionalRange!R ||
              isForwardRange!R && isInfinite!R);

R r = void;
auto e = r[1]; // can index
static assert(is(typeof(e) == typeof(r.front))); // 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(r.front) == 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(r.front) == typeof(r[$ - 1])));
}

The semantics of a random-access range (not checkable during compilation) are assumed to be the following (r is an object of type R):
  • r.opIndex(n) returns a reference to the nth element in the range.

Although char[] and wchar[] (as well as their qualified versions including string and wstring) are arrays, isRandomAccessRange yields false for them because they use variable-length encodings (UTF-8 and UTF-16 respectively). These types are bidirectional ranges only.

template hasMobileElements(R)
Returns true iff R supports the moveFront primitive, as well as moveBack and 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 moveFront and friends.

template ElementType(R)
The element type of R. R does not have to be a range. The element type is determined as the type yielded by r.front for an object r of type R. For example, ElementType!(T[]) is T if T[] isn't a narrow string; if it is, the element type is dchar. If R doesn't have front, ElementType!R is void.

template ElementEncodingType(R)
The encoding element type of R. For narrow strings (char[], wchar[] and their qualified variants including string and wstring), ElementEncodingType is the character type of the string. For all other types, ElementEncodingType is the same as ElementType.

template hasSwappableElements(R)
Returns true if R is a forward range and has swappable elements. The following code should compile for any range with swappable elements.

R r;
static assert(isForwardRange!(R));   // range is forward
swap(r.front, r.front);              // can swap elements of the range

template hasAssignableElements(R)
Returns true if R is a forward range and has mutable elements. The following code should compile for any range with assignable elements.

R r;
static assert(isForwardRange!R);  // range is forward
auto e = r.front;
r.front = e;                      // can assign elements of the range

template hasLvalueElements(R)
Tests whether R has lvalue elements. These are defined as elements that can be passed by reference and have their address taken.

template hasLength(R)
Returns true if R has a length member that returns an integral type. R does not have to be a range. Note that 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 (char[], wchar[], and their qualified derivatives) do define a length property, hasLength yields 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 isInfinite(R)
Returns true if R is an infinite input range. An infinite input range is an input range that has a statically-defined enumerated member called empty that is always false, for example:

struct MyInfiniteRange
{
    enum bool empty = false;
    ...
}

template hasSlicing(R)
Returns true if R offers a slicing operator with integral boundaries that returns a forward range type.

For finite ranges, the result of opSlice must be of the same type as the original range type. If the range defines opDollar, then it must support subtraction.

For infinite ranges, when not using opDollar, the result of opSlice must be the result of take or takeExactly on the original range (they both return the same type for infinite ranges). However, when using opDollar, the result of opSlice must be that of the original range type.

The following code must compile for hasSlicing to be 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])));

auto walkLength(Range)(Range range);
auto walkLength(Range)(Range range, const size_t upTo);
This is a best-effort implementation of length for any kind of range.

If hasLength!Range, simply returns range.length without checking upTo (when specified).

Otherwise, walks the range through its length and returns the number of elements seen. Performes Ο(n) evaluations of range.empty and range.popFront(), where n is the effective length of range.

The 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 upTo is specified, stops if upTo steps have been taken and returns upTo.

Infinite ranges are compatible, provided the parameter upTo is specified, in which case the implementation simply returns upTo.

auto retro(Range)(Range r);
Iterates a bidirectional range backwards. The original range can be accessed by using the source property. Applying retro twice to the same range yields the original range.

Example:
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);

auto stride(Range)(Range r, size_t n);
Iterates range r with stride n. If the range is a random-access range, moves by indexing into the range; otehrwise, moves by successive calls to popFront. Applying stride twice to the same range results in a stride that with a step that is the product of the two applications.

Throws:
Exception if n == 0.

Example:
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));

auto chain(Ranges...)(Ranges rs);
Spans multiple ranges in sequence. The function chain takes any number of ranges and returns a 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 front, popFront, and empty primitives. If all input ranges offer random access and length, Chain offers them as well.

If only one range is offered to Chain or chain, the Chain type exits the picture by aliasing itself directly to that range's type.

Example:
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][]));

auto roundRobin(Rs...)(Rs rs);
roundRobin(r1, r2, r3) yields r1.front, then r2.front, then r3.front, after which it pops off one element from each and continues again from r1. For example, if two ranges are involved, it alternately yields elements off the two ranges. roundRobin stops after it has consumed all ranges (skipping over the ones that finish early).

Example:
int[] a = [ 1, 2, 3, 4];
int[] b = [ 10, 20 ];
assert(equal(roundRobin(a, b), [1, 10, 2, 20, 3, 4]));

auto radial(Range, I)(Range r, I startingIndex);
auto radial(R)(R r);
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.

Example:
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 ]));

struct Take(Range) if (isInputRange!(Unqual!(Range)) && !(!isInfinite!(Unqual!(Range)) && hasSlicing!(Unqual!(Range)) || is(Range T == Take!(T))));
Take!(R) take(R)(R input, size_t n);
Lazily takes only up to n elements of a range. This is particularly useful when using with infinite ranges. If the range offers random access and length, Take offers them as well.

Example:
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 ][]));

auto takeExactly(R)(R range, size_t n);
Similar to take, but assumes that range has at least n elements. Consequently, the result of takeExactly(range, n) always defines the length property (and initializes it to n) even when range itself does not define length.

The result of takeExactly is identical to that of take in cases where the original range defines length or is infinite.

auto takeOne(R)(R source);
Returns a range with at most one element; for example, takeOne([42, 43, 44]) returns a range consisting of the integer 42. Calling popFront() off that range renders it empty.

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

In effect takeOne(r) is somewhat equivalent to 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 takeOne is a random-access range with length regardless of R's capabilities (another feature that distinguishes takeOne from take).

auto takeNone(R)();
Returns an empty range which is statically known to be empty and is guaranteed to have length and be random access regardless of R's capabilities.

Examples:
auto range = takeNone!(int[])();
assert(range.length == 0);
assert(range.empty);

auto takeNone(R)(R range);
Creates an empty range from the given range in Ο(1). If it can, it will return the same range type. If not, it will return takeExactly(range, 0).

Examples:
assert(takeNone([42, 27, 19]).empty);
assert(takeNone("dlang.org").empty);
assert(takeNone(filter!"true"([42, 27, 19])).empty);

R drop(R)(R range, size_t n);
R dropBack(R)(R range, size_t n);
Convenience function which calls range.popFrontN(n) and returns range. drop makes it easier to pop elements from a range and then pass it to another function within a single expression, whereas popFrontN would require multiple statements.

dropBack provides the same functionality but instead calls range.popBackN(n).

Note:
drop and dropBack will only pop up to n elements but will stop if the range is empty first.

Examples:
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 "));

//Remove all but the first two elements
auto a = DList!int(0, 1, 9, 9, 9);
a.remove(a[].drop(2));
assert(a[].equal(a[].take(2)));

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

//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)));

R dropExactly(R)(R range, size_t n);
R dropBackExactly(R)(R range, size_t n);
Similar to drop and dropBack but they call range.popFrontExactly(n) and range.popBackExactly(n) instead.

Note:
Unlike drop, dropExactly will assume that the range holds at least n elements. This makes dropExactly faster than drop, but it also means that if range does not contain at least n elements, it will attempt to call popFront on an empty range, which is undefined behavior. So, only use popFrontExactly when it is guaranteed that range holds at least n elements.

R dropOne(R)(R range);
R dropBackOne(R)(R range);
Convenience function which calls range.popFront() and returns range. dropOne makes it easier to pop an element from a range and then pass it to another function within a single expression, whereas popFront would require multiple statements.

dropBackOne provides the same functionality but instead calls range.popBack().

Example:
auto dl = DList!int(9, 1, 2, 3, 9);
assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));

size_t popFrontN(Range)(ref Range r, size_t n);
size_t popBackN(Range)(ref Range r, size_t n);
Eagerly advances r itself (not a copy) up to n times (by calling r.popFront(). popFrontN takes r by ref, so it mutates the original range. Completes in Ο(1) steps for ranges that support slicing and have length. Completes in Ο(n) time for all other ranges.

Returns:
How much r was actually advanced, which may be less than n if r did not have at least n element.

popBackN will behave the same but instead removes elements from the back of the (bidirectional) range instead of the front.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popFrontN(2);
assert(a == [ 3, 4, 5 ]);
a.popFrontN(7);
assert(a == [ ]);

int[] a = [ 1, 2, 3, 4, 5 ];
a.popBackN(2);
assert(a == [ 1, 2, 3 ]);
a.popBackN(7);
assert(a == [ ]);

void popFrontExactly(Range)(ref Range r, size_t n);
void popBackExactly(Range)(ref Range r, size_t n);
Eagerly advances r itself (not a copy) exactly n times (by calling r.popFront. popFrontExactly takes r by ref, so it mutates the original range. Completes in Ο(1) steps for ranges that support slicing, and have either length or are infinite. Completes in Ο(n) time for all other ranges.

Note:
Unlike popFrontN, popFrontExactly will assume that the range holds at least n elements. This makes popFrontExactly faster than popFrontN, but it also means that if range does not contain at least n elements, it will attempt to call popFront on an empty range, which is undefined behavior. So, only use popFrontExactly when it is guaranteed that range holds at least n elements.

popBackExactly will behave the same but instead removes elements from the back of the (bidirectional) range instead of the front.

struct Repeat(T);
Repeat!(T) repeat(T)(T value);
Repeats one value forever.

Example:
enforce(equal(take(repeat(5), 4), [ 5, 5, 5, 5 ][]));

T front();
T back();
bool empty;
void popFront();
void popBack();
Repeat!(T) save();
T opIndex(size_t);
Range primitive implementations.

Take!(Repeat!(T)) repeat(T)(T value, size_t n);
Repeats value exactly n times. Equivalent to take(repeat(value), n).

Take!(Repeat!(T)) replicate(T)(T value, size_t n);
Deprecated. It will be removed in January 2013. Please use repeat instead.

struct Cycle(Range) if (isForwardRange!(Unqual!(Range)) && !isInfinite!(Unqual!(Range)));
Cycle!(R) cycle(R)(R input);
Cycle!(R) cycle(R)(R input, size_t index = 0);
Repeats the given forward range ad infinitum. If the original range is infinite (fact that would make Cycle the identity application), Cycle detects that and aliases itself to the range type itself. If the original range has random access, Cycle offers random access and also offers a constructor taking an initial position index. Cycle works with static arrays in addition to ranges, mostly for performance reasons.

Example:
assert(equal(take(cycle([1, 2][]), 5), [ 1, 2, 1, 2, 1 ][]));

Tip:
This is a great way to implement simple circular buffers.

struct Zip(Ranges...) if (Ranges.length && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)));
auto zip(R...)(R ranges);
auto zip(R...)(StoppingPolicy sp, R ranges);
Iterate several ranges in lockstep. The element type is a proxy tuple that allows accessing the current element in the nth range by using e[n].

Example:
   int[] a = [ 1, 2, 3 ];
   string[] b = [ "a", "b", "c" ];
   // prints 1:a 2:b 3:c
   foreach (e; zip(a, b))
   {
   write(e[0], ':', e[1], ' ');
   }

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, Zip is extremely powerful because it allows manipulating several ranges in lockstep. For example, the following code sorts two arrays in parallel:

   int[] a = [ 1, 2, 3 ];
   string[] b = [ "a", "b", "c" ];
   sort!("a[0] > b[0]")(zip(a, b));
   assert(a == [ 3, 2, 1 ]);
   assert(b == [ "c", "b", "a" ]);

this(R rs, StoppingPolicy s = StoppingPolicy.shortest);
Builds an object. Usually this is invoked indirectly by using the zip function.

bool empty;
Returns true if the range is at end. The test depends on the stopping policy.

ElementType front();
Returns the current iterated element.

void front(ElementType v);
Sets the front of all iterated ranges.

ElementType moveFront();
Moves out the front.

ElementType back();
Returns the rightmost element.

ElementType moveBack();
Moves out the back.

Returns the rightmost element.

void back(ElementType v);
Returns the current iterated element.

Returns the rightmost element.

void popFront();
Advances to the next element in all controlled ranges.

void popBack();
Calls popBack for all controlled ranges.

@property auto length();
Returns the length of this range. Defined only if all ranges define length.

alias length opDollar;
Returns the length of this range. Defined only if all ranges define length.

Zip opSlice(size_t from, size_t to);
Returns a slice of the range. Defined only if all range define slicing.

ElementType opIndex(size_t n);
Returns the nth element in the composite range. Defined if all ranges offer random access.

void opIndexAssign(ElementType v, size_t n);
Assigns to the nth element in the composite range. Defined if all ranges offer random access.

ElementType moveAt(size_t n);
Destructively reads the nth element in the composite range. Defined if all ranges offer random access.

enum StoppingPolicy;
Dictates how iteration in a Zip should stop. By default stop at the end of the shortest of all ranges.

shortest
Stop when the shortest range is exhausted

longest
Stop when the longest range is exhausted

requireSameLength
Require that all ranges are equal

struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Ranges)));
Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges);
Lockstep!(Ranges) lockstep(Ranges...)(Ranges ranges, StoppingPolicy s);
Iterate multiple ranges in lockstep using a foreach loop. If only a single range is passed in, the Lockstep aliases itself away. If the ranges are of different lengths and s == StoppingPolicy.shortest stop after the shortest range is empty. If the ranges are of different lengths and s == StoppingPolicy.requireSameLength, throw an exception. s may not be StoppingPolicy.longest, and passing this will throw an exception.

By default StoppingPolicy is set to StoppingPolicy.shortest.

BUGS:
If a range does not offer lvalue access, but ref is used in the foreach loop, it will be silently accepted but any modifications to the variable will not be propagated to the underlying range.

Examples:
   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]);

   // Lockstep also supports iterating with an index variable:
   foreach(index, a, b; lockstep(arr1, arr2)) {
       writefln("Index %s:  a = %s, b = %s", index, a, b);
   }

struct Recurrence(alias fun, StateType, size_t stateSize);
Recurrence!(fun, CommonType!(State), State.length) recurrence(alias fun, State...)(State initial);
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 Recurrence itself is seldom used directly; most often, recurrences are obtained by calling the function recurrence.

When calling 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.

If the function is passed in string form, the state has name "a" and the zero-based index in the recurrence has name "n". The given string must return the desired value for a[n] given a[n - 1], a[n - 2], a[n - 3],..., a[n - stateSize]. The state size is dictated by the number of arguments passed to the call to recurrence. The Recurrence struct itself takes care of managing the recurrence's state and shifting it appropriately.

Example:
// 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);
// print the first 10 Fibonacci numbers
foreach (e; take(fib, 10)) { writeln(e); }
// print the first 10 factorials
foreach (e; take(recurrence!("a[n-1] * n")(1), 10)) { writeln(e); }

struct Sequence(alias fun, State);
Sequence!(fun, Tuple!(State)) sequence(alias fun, State...)(State args);
Sequence is similar to Recurrence except that iteration is presented in the so-called closed form. This means that the nth element in the series is computable directly from the initial values and n itself. This implies that the interface offered by Sequence is a random-access range, as opposed to the regular Recurrence, which only offers forward iteration.

The state of the sequence is stored as a Tuple so it can be heterogeneous.

Example:
   // a[0] = 1, a[1] = 2, a[n] = a[0] + n * a[1]
   auto odds = sequence!("a[0] + n * a[1]")(1, 2);

auto iota(B, E, S)(B begin, E end, S step);
auto iota(B, E)(B begin, E end);
auto iota(B, E)(B begin, E end);
auto iota(E)(E end);
Returns a range that goes through the numbers begin, begin + step, begin + 2 * step, ..., up to and excluding end. The range offered is a random access range. The two-arguments version has step = 1. If begin < end && step < 0 or begin > end && step > 0 or begin == end, then an empty range is returned.

Throws:
Exception if begin != end && step == 0, an exception is thrown.

Example:
   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]));

enum TransverseOptions;
Options for the FrontTransversal and Transversal ranges (below).

assumeJagged
When transversed, the elements of a range of ranges are assumed to have different lengths (e.g. a jagged array).

enforceNotJagged
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.

assumeNotJagged
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.

struct FrontTransversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);
FrontTransversal!(RangeOfRanges, opt) frontTransversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr);
Given a range of ranges, iterate transversally through the first elements of each of the enclosed ranges.

Example:
   int[][] x = new int[][2];
   x[0] = [1, 2];
   x[1] = [3, 4];
   auto ror = frontTransversal(x);
   assert(equal(ror, [ 1, 3 ][]));

this(RangeOfRanges input);
Construction from an input.

bool empty;
@property ref auto front();
ElementType moveFront();
void popFront();
Forward range primitives.

FrontTransversal save();
Duplicates this frontTransversal. Note that only the encapsulating range of range will be duplicated. Underlying ranges will not be duplicated.

@property ref auto back();
void popBack();
ElementType moveBack();
Bidirectional primitives. They are offered if isBidirectionalRange!RangeOfRanges.

ref auto opIndex(size_t n);
ElementType moveAt(size_t n);
void opIndexAssign(ElementType val, size_t n);
Random-access primitive. It is offered if isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged).

typeof(this) opSlice(size_t lower, size_t upper);
Slicing if offered if RangeOfRanges supports slicing and all the conditions for supporting indexing are met.

struct Transversal(Ror, TransverseOptions opt = TransverseOptions.assumeJagged);
Transversal!(RangeOfRanges, opt) transversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr, size_t n);
Given a range of ranges, iterate transversally through the the nth element of each of the enclosed ranges. All elements of the enclosing range must offer random access.

Example:
   int[][] x = new int[][2];
   x[0] = [1, 2];
   x[1] = [3, 4];
   auto ror = transversal(x, 1);
   assert(equal(ror, [ 2, 4 ][]));

this(RangeOfRanges input, size_t n);
Construction from an input and an index.

bool empty;
@property ref auto front();
E moveFront();
@property auto front(E val);
void popFront();
typeof(this) save();
Forward range primitives.

@property ref auto back();
void popBack();
E moveBack();
@property auto back(E val);
Bidirectional primitives. They are offered if isBidirectionalRange!RangeOfRanges.

ref auto opIndex(size_t n);
E moveAt(size_t n);
void opIndexAssign(E val, size_t n);
size_t length();
alias length opDollar;
Random-access primitive. It is offered if isRandomAccessRange!RangeOfRanges && (opt == TransverseOptions.assumeNotJagged || opt == TransverseOptions.enforceNotJagged).

typeof(this) opSlice(size_t lower, size_t upper);
Slicing if offered if RangeOfRanges supports slicing and all the conditions for supporting indexing are met.

struct Indexed(Source, Indices) if (isRandomAccessRange!(Source) && isInputRange!(Indices) && is(typeof(Source.init[ElementType!(Indices).init])));
Indexed!(Source, Indices) indexed(Source, Indices)(Source source, Indices indices);
This struct takes two ranges, source and indices, and creates a view of source as if its elements were reordered according to indices. indices may include only a subset of the elements of source and may also repeat elements.

Source must be a random access range. The returned range will be bidirectional or random-access if Indices is bidirectional or random-access, respectively.

Examples:
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]));

// 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);

@property ref auto front();
void popFront();
typeof(this) save();
@property ref auto front(ElementType!(Source) newVal);
auto moveFront();
@property ref auto back();
void popBack();
@property ref auto back(ElementType!(Source) newVal);
auto moveBack();
size_t length();
ref auto opIndex(size_t index);
typeof(this) opSlice(size_t a, size_t b);
auto opIndexAssign(ElementType!(Source) newVal, size_t index);
auto moveAt(size_t index);
Range primitives

Source source();
Returns the source range.

Indices indices();
Returns the indices range.

size_t physicalIndex(size_t logicalIndex);
Returns the physical index into the source range corresponding to a given logical index. This is useful, for example, when indexing an Indexed without adding another layer of indirection.

Examples:
        auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
        assert(ind.physicalIndex(0) == 1);

struct Chunks(Source) if (isInputRange!(Source) && hasSlicing!(Source) && hasLength!(Source));
Chunks!(Source) chunks(Source)(Source source, size_t chunkSize);
This range iterates over fixed-sized chunks of size chunkSize of a source range. Source must be an input range with slicing and length. If source.length is not evenly divisible by chunkSize, the back element of this range will contain fewer than chunkSize elements.

Examples:
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);

this(Source source, size_t chunkSize);

@property auto front();
void popFront();
bool empty();
typeof(this) save();
auto opIndex(size_t index);
typeof(this) opSlice(size_t lower, size_t upper);
size_t length();
@property auto back();
void popBack();
Range primitives.

ElementType!(R) moveFront(R)(R r);
Moves the front of r out and returns it. Leaves r.front in a destroyable state that does not allocate any resources (usually equal to its .init value).

ElementType!(R) moveBack(R)(R r);
Moves the back of r out and returns it. Leaves r.back in a destroyable state that does not allocate any resources (usually equal to its .init value).

ElementType!(R) moveAt(R, I)(R r, I i);
Moves element at index i of r out and returns it. Leaves r.front in a destroyable state that does not allocate any resources (usually equal to its .init value).

interface InputRange(E);
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 isInputRange and friends check for conformance to structural interfaces, not for implementation of these interface types.

Examples:
 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);

Limitations:
These interfaces are not capable of forwarding 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:
inputRangeObject

E front();

E moveFront();

void popFront();

bool empty();

int opApply(int delegate(E));
int opApply(int delegate(size_t, E));
foreach iteration uses opApply, since one delegate call per loop iteration is faster than three virtual function calls.

interface ForwardRange(E): InputRange!(E);
Interface for a forward range of type E.

ForwardRange!(E) save();

interface BidirectionalRange(E): ForwardRange!(E);
Interface for a bidirectional range of type E.

BidirectionalRange!(E) save();

E back();

E moveBack();

void popBack();

interface RandomAccessFinite(E): BidirectionalRange!(E);
Interface for a finite random access range of type E.

RandomAccessFinite!(E) save();

E opIndex(size_t);

E moveAt(size_t);

size_t length();

alias length opDollar;

RandomAccessFinite!(E) opSlice(size_t, size_t);

interface RandomAccessInfinite(E): ForwardRange!(E);
Interface for an infinite random access range of type E.

E moveAt(size_t);

RandomAccessInfinite!(E) save();

E opIndex(size_t);

interface InputAssignable(E): InputRange!(E);
Adds assignable elements to InputRange.

void front(E newVal);

interface ForwardAssignable(E): InputAssignable!(E), ForwardRange!(E);
Adds assignable elements to ForwardRange.

ForwardAssignable!(E) save();

interface BidirectionalAssignable(E): ForwardAssignable!(E), BidirectionalRange!(E);
Adds assignable elements to BidirectionalRange.

BidirectionalAssignable!(E) save();

void back(E newVal);

interface RandomFiniteAssignable(E): RandomAccessFinite!(E), BidirectionalAssignable!(E);
Adds assignable elements to RandomAccessFinite.

RandomFiniteAssignable!(E) save();

void opIndexAssign(E val, size_t index);

interface OutputRange(E);
Interface for an output range of type E. Usage is similar to the InputRange interface and descendants.

void put(E);

class OutputRangeObject(R, E...): staticMap!(OutputRange, E);
Implements the OutputRange interface for all types E and wraps the put method for each type E in a virtual function.

template MostDerivedInputRange(R) if (isInputRange!(Unqual!(R)))
Returns the interface type that best matches R.

template InputRangeObject(R) if (isInputRange!(Unqual!(R)))
Implements the most derived interface that R works with and wraps all relevant range primitives in virtual functions. If R is already derived from the InputRange interface, aliases itself away.

InputRangeObject!(R) inputRangeObject(R)(R range);
Convenience function for creating an InputRangeObject of the proper type. See InputRange for an example.

template outputRangeObject(E...)
Convenience function for creating an OutputRangeObject with a base range of type R that accepts types E.

Examples:
 uint[] outputArray;
 auto app = appender(&outputArray);
 auto appWrapped = outputRangeObject!(uint, uint[])(app);
 static assert(is(typeof(appWrapped) : OutputRange!(uint[])));
 static assert(is(typeof(appWrapped) : OutputRange!(uint)));

OutputRangeObject!(R, E) outputRangeObject(R)(R range);

template isTwoWayCompatible(alias fn, T1, T2)
Returns true if 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());

enum SearchPolicy;
Policy used with the searching primitives lowerBound, upperBound, and equalRange of SortedRange below.

trot
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 Ο(sqrt(n)) time. Use it when you are reasonably confident that the value is around the beginning of the range.

gallop
Performs a 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 Ο(log(n)) time.

binarySearch
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 Ο(log(n)) time but is less cache friendly than gallop for large ranges. The binarySearch policy is used as the last step of trot, gallop, trotBackwards, and gallopBackwards strategies.

trotBackwards
Similar to trot but starts backwards. Use it when confident that the value is around the end of the range.

gallopBackwards
Similar to gallop but starts backwards. Use it when confident that the value is around the end of the range.

struct SortedRange(Range, alias pred = "a < b") if (isRandomAccessRange!(Range) && hasLength!(Range));
Represents a sorted random-access range. In addition to the regular range primitives, supports fast operations using binary search. To obtain a SortedRange from an unsorted range r, use std.algorithm.sort which sorts r in place and returns the corresponding SortedRange. To construct a SortedRange from a range r that is known to be already sorted, use assumeSorted described below.

Example:
   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 ]);

SortedRange could accept ranges weaker than random-access, but it is unable to provide interesting functionality for them. Therefore, 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 SortedRange in ways that break its sortedness, SortedRange will work erratically.

Example:
   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

bool empty();
@property auto save();
@property auto front();
void popFront();
@property auto back();
void popBack();
auto opIndex(size_t i);
auto opSlice(size_t a, size_t b);
size_t length();
Range primitives.

auto release();
Releases the controlled range and returns it.

auto lowerBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value);
This function uses binary search with policy sp to find the largest left subrange on which pred(x, value) is true for all x (e.g., if pred is "less than", returns the portion of the range with elements strictly smaller than value). The search schedule and its complexity are documented in SearchPolicy. See also STL's lower_bound.

Example:
   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 ]));

auto upperBound(SearchPolicy sp = SearchPolicy.binarySearch, V)(V value);
This function uses binary search with policy sp to find the largest right subrange on which pred(value, x) is true for all x (e.g., if pred is "less than", returns the portion of the range with elements strictly greater than value). The search schedule and its complexity are documented in SearchPolicy. See also STL's upper_bound.

Example:
   auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
   auto p = a.upperBound(3);
   assert(equal(p, [4, 4, 5, 6]));

auto equalRange(V)(V value);
Returns the subrange containing all elements e for which both pred(e, value) and pred(value, e) evaluate to false (e.g., if pred is "less than", returns the portion of the range with elements equal to value). Uses a classic binary search with interval halving until it finds a value that satisfies the condition, then uses SearchPolicy.gallopBackwards to find the left boundary and 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 Ο(log(n)) time. See also STL's equal_range.

Example:
   auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
   auto r = equalRange(a, 3);
   assert(equal(r, [ 3, 3, 3 ]));

auto trisect(V)(V value);
Returns a tuple r such that r[0] is the same as the result of lowerBound(value), r[1] is the same as the result of equalRange(value), and r[2] is the same as the result of upperBound(value). The call is faster than computing all three separately. Uses a search schedule similar to equalRange. Completes the entire search in Ο(log(n)) time.

Example:
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 ]));

bool contains(V)(V value);
Returns true if and only if value can be found in range, which is assumed to be sorted. Performs Ο(log(r.length)) evaluations of pred. See also STL's binary_search.

alias contains canFind;
Deprecated. It will be removed in January 2013. Please use contains instead.

auto assumeSorted(alias pred = "a < b", R)(R r);
Assumes r is sorted by predicate pred and returns the corresponding SortedRange!(pred, R) having r as support. To keep the checking costs low, the cost is Ο(1) in release mode (no checks for sortedness are performed). In debug mode, a few random elements of r are checked for sortedness. The size of the sample is proportional Ο(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 Ο(n), use std.algorithm.isSorted.

struct RefRange(R) if (isForwardRange!(R));
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 not copied but is consumed as if it were a reference type.

Note that save works as normal and operates on a new range, so if save is ever called on the RefRange, then no operations on the saved range will affect the original.

Examples:
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(wrapped2.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");

pure nothrow @safe this(R* range);

auto opAssign(RefRange rhs);
This does not assign the pointer of rhs to this RefRange. Rather it assigns the range pointed to by rhs to the range pointed to by this RefRange. This is because any operation on a RefRange is the same is if it occurred to the original range. The one exception is when a RefRange is assigned null either directly or because rhs is null. In that case, RefRange no longer refers to the original range but is null.

Examples:
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]);

auto opAssign(typeof(null) rhs);

inout pure nothrow @safe inout(R*) ptr();
A pointer to the wrapped range.

@property auto front();
const @property auto front();
@property auto front(ElementType!(R) value);

bool empty();
const bool empty();

void popFront();

@property auto save();
const @property auto save();
auto opSlice();
const auto opSlice();

@property auto back();
const @property auto back();
@property auto back(ElementType!(R) value);
void popBack();
Only defined if isBidirectionalRange!R is true.

ref auto opIndex(IndexType)(IndexType index);
const ref auto opIndex(IndexType)(IndexType index);
Only defined if isRandomAccesRange!R is true.

auto moveFront();
Only defined if hasMobileElements!R and isForwardRange!R are true.

auto moveBack();
Only defined if hasMobileElements!R and isBidirectionalRange!R are true.

auto moveAt(IndexType)(IndexType index);
Only defined if hasMobileElements!R and isRandomAccessRange!R are true.

@property auto length();
const @property auto length();
Only defined if hasLength!R is true.

auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end);
const auto opSlice(IndexType1, IndexType2)(IndexType1 begin, IndexType2 end);
Only defined if hasSlicing!R is true.

auto refRange(R)(R* range);
Helper function for constructing a RefRange.

If the given range is not a forward range or it is a class type (and thus is already a reference type), then the original range is returned rather than a RefRange.

Copyright by authors 2008-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.regex

Regular expressions are a commonly used method of pattern matching on strings, with 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 & replace in text processing utilities.

Synposis:
  import std.regex;
  import std.stdio;
  void main()
  {
      // Print out all possible dd/mm/yy(yy) dates found in user input.
      // g - global: find all matches.
      auto r = regex(r"\b[0-9][0-9]?/[0-9][0-9]?/[0-9][0-9](?:[0-9][0-9])?\b", "g");
      foreach(line; stdin.byLine)
      {
        // Match returns a range that can be iterated
        // to get all subsequent matches.
        foreach(c; match(line, r))
            writeln(c.hit);
      }
  }
  ...

  // Create a static regex at compile-time, which contains fast native code.
  enum ctr = ctRegex!(`^.*/([^/]+)/?$`);

  // It works just like a normal regex:
  auto m2 = match("foo/bar", ctr);   // First match found here, if any
  assert(m2);   // Be sure to check if there is a match before examining contents!
  assert(m2.captures[1] == "bar");   // Captures is a range of submatches: 0 = full match.

  ...

  // The result of the match is directly testable with if/assert/while.
  // e.g. test if a string consists of letters:
  assert(match("Letter", `^\p{L}+$`));

The general usage guideline is to keep regex complexity on the side of simplicity, as its capabilities reside in purely character-level manipulation, and as such are ill-suited for tasks involving higher level invariants like matching an integer number 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. Thankfully, nowadays the web is bustling with resources to help newcomers, and a good reference with tutorial on regular expressions can be found.

This library uses an ECMAScript syntax flavor with the following extensions:
  • Named subexpressions, with Python syntax.
  • Unicode properties such as Scripts, Blocks and common binary properties e.g Alphabetic, White_Space, Hex_Digit etc.
  • Arbitrary length and complexity lookbehind, including lookahead in lookbehind and vise-versa.

Pattern syntax

std.regex operates on codepoint level, 'character' in this table denotes a single unicode codepoint.
Pattern element | Semantics
Atoms | Match single characters
any character except [{|*+?()^$ | Matches the character itself.
. | In single line mode matches any charcter. Otherwise it matches any character except '\n' and '\r'.
[class] | Matches a single character that belongs to this character class.
[^class] | Matches a single character that does not belong to this character class.
\cC | Matches the control character corresponding to letter C
\xXX | Matches a character with hexadecimal value of XX.
\uXXXX | Matches a character with hexadecimal value of XXXX.
\U00YYYYYY | Matches a character with hexadecimal value of YYYYYY.
\f | Matches a formfeed character.
\n | Matches a linefeed character.
\r | Matches a carriage return character.
\t | Matches a tab character.
\v | Matches a vertical tab character.
\d | Matches any unicode digit.
\D | Matches any character except unicode digits.
\w | Matches any word character (note: this includes numbers).
\W | Matches any non-word character.
\s | Matches whitespace, same as \p{White_Space}.
\S | Matches any character except those recognized as \s .
\\ | Matches \ character.
\c where c is one of [|*+?() | Matches the character c itself.
\p{PropertyName} | Matches a character that belongs to the unicode PropertyName set. Single letter abbreviations can be used without surrounding {,}.
\P{PropertyName} | Matches a character that does not belong to the unicode PropertyName set. Single letter abbreviations can be used without surrounding {,}.
\p{InBasicLatin} | Matches any character that is part of the BasicLatin unicode block.
\P{InBasicLatin} | Matches any character except ones in the BasicLatin unicode block.
\p{Cyrilic} | Matches any character that is part of Cyrilic script.
\P{Cyrilic} | Matches any character except ones in Cyrilic script.
Quantifiers | Specify repetition of other elements
* | Matches previous character/subexpression 0 or more times. Greedy version - tries as many times as possible.
*? | Matches previous character/subexpression 0 or more times. Lazy version - stops as early as possible.
+ | Matches previous character/subexpression 1 or more times. Greedy version - tries as many times as possible.
+? | Matches previous character/subexpression 1 or more times. Lazy version - stops as early as possible.
{n} | Matches previous character/subexpression exactly n times.
{n,} | Matches previous character/subexpression n times or more. Greedy version - tries as many times as possible.
{n,}? | Matches previous character/subexpression n times or more. Lazy version - stops as early as possible.
{n,m} | Matches previous character/subexpression n to m times. Greedy version - tries as many times as possible, but no more than m times.
{n,m}? | Matches previous character/subexpression n to m times. Lazy version - stops as early as possible, but no less then n times.
Other | Subexpressions & alternations
(regex) | Matches subexpression regex, saving matched portion of text for later retrieval.
(?:regex) | Matches subexpression regex, not saving matched portion of text. Useful to speed up matching.
A|B | Matches subexpression A, or failing that, matches B.
(?P<name>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.
Assertions | Match position rather than character
^ | Matches at the begining of input or line (in multiline mode).
$ | Matches at the end of input or line (in multiline mode).
\b | Matches at word boundary.
\B | Matches when not at word boundary.
(?=regex) | Zero-width lookahead assertion. Matches at a point where the subexpression regex could be matched starting from the current position.
(?!regex) | Zero-width negative lookahead assertion. Matches at a point where the subexpression regex could not be matched starting from the current position.
(?<=regex) | Zero-width lookbehind assertion. Matches at a point where the subexpression regex could be matched ending at the current position (matching goes backwards).
(?<!regex) | Zero-width negative lookbehind assertion. Matches at a point where the subexpression regex could not be matched ending at the current position (matching goes backwards).

Character classes

Pattern element | Semantics
Any atom | Has the same meaning as outside of a character class.
a-z | Includes characters a, b, c, ..., z.
[a||b], [a--b], [a~~b], [a&&b] | Where a, b are arbitrary classes, means union, set difference, symmetric set difference, and intersection respectively. Any sequence of character class elements implicitly forms a union.

Regex flags

Flag | Semantics
g | Global regex, repeat over the whole input.
i | Case insensitive matching.
m | Multi-line mode, match ^, $ on start and end line separators as well as start and end of input.
s | Single-line mode, makes . match '\n' and '\r' as well.
x | Free-form syntax, ignores whitespace in pattern, useful for formatting complex regular expressions.

Unicode support

This library provides full Level 1 support* according to UTS 18. Specifically:
  • 1.1 Hex notation via any of \uxxxx, \U00YYYYYY, \xZZ.
  • 1.2 Unicode properties.
  • 1.3 Character classes with set operations.
  • 1.4 Word boundaries use the full set of "word" characters.
  • 1.5 Using simple casefolding to match case insensitively across the full range of codepoints.
  • 1.6 Respecting line breaks as any of \u000A | \u000B | \u000C | \u000D | \u0085 | \u2028 | \u2029 | \u000D\u000A.
  • 1.7 Operating on codepoint level.
*With exception of point 1.1.1, as of yet, normalization of input is expected to be enforced by user.

Slicing

All matches returned by pattern matching functionality in this library are slices of the original input, with the notable exception of the replace family of functions which generate a new string from the input.

License:
Boost License 1.0.

Authors:
Dmitry Olshansky,

API and utility constructs are based on original std.regex by Walter Bright and Andrei Alexandrescu.

Source:
std/regex.d

struct Regex(Char);
Regex object holds regular expression pattern in compiled form. Instances of this object are constructed via calls to regex. This is an intended form for caching and storage of frequently used regular expressions.

const nothrow bool empty();
Test if this object doesn't contain any compiled pattern.

Example:
        Regex!char r;
        assert(r.empty);
        r = regex(""); // Note: "" is a valid regex pattern.
        assert(!r.empty);

struct StaticRegex(Char);
A StaticRegex is Regex object that contains specially generated machine code to speed up matching. Implicitly convertible to normal Regex, however doing so will result in losing this additional capability.

struct Captures(R, DIndex = size_t) if (isSomeString!(R));
Captures object contains submatches captured during a call to match or iteration over RegexMatch range.

First element of range is the whole match.

Example, showing basic operations on Captures:
    import std.regex;
    import std.range;

    void main()
    {
        auto m = match("@abc#", regex(`(\w)(\w)(\w)`));
        auto c = m.captures;
        assert(c.pre == "@"); // Part of input preceeding 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);
    }

R pre();
Slice of input prior to the match.

R post();
Slice of input immediately after the match.

R hit();
Slice of matched portion of input.

R front();
R back();
void popFront();
void popBack();
const bool empty();
R opIndex()(size_t i);
Range interface.

R opIndex(String)(String i);
Lookup named submatch.

        import std.regex;
        import std.range;

        auto m = match("a = 42;", regex(`(?P<var>\w+)\s*=\s*(?P<value>\d+);`));
        auto c = m.captures;
        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");

const size_t length();
Number of matches in this object.

@property ref auto captures();
A hook for compatibility with original std.regex.

struct RegexMatch(R, alias Engine = ThompsonMatcher) if (isSomeString!(R));
A regex engine state, as returned by match family of functions.

Effectively it's a forward range of Captures!R, produced by lazily searching for matches in a given input.

alias Engine specifies an engine type to use during matching, and is automatically deduced in a call to match/bmatch.

R pre();
R post();
R hit();
Shorthands for front.pre, front.post, front.hit.

@property auto front();
void popFront();
auto save();
Functionality for processing subsequent matches of global regexes via range interface:
        import std.regex;
        auto m = match("Hello, world!", regex(`\w+`, "g"));
        assert(m.front.hit == "Hello");
        m.popFront();
        assert(m.front.hit == "world");
        m.popFront();
        assert(m.empty);

bool empty();
Test if this match object is empty.

T opCast(T : bool)();
Same as !(x.empty), provided for its convenience in conditional statements.

@property auto captures();
Same as .front, provided for compatibility with original std.regex.

auto regex(S)(S pattern, const(char)[] flags = "");
Compile regular expression pattern for the later execution.

Returns:
Regex object that works on inputs having the same character width as pattern.

Parameters:
pattern | Regular expression
flags | The attributes (g, i, m and x accepted)

Throws:
RegexException if there were any errors during compilation.

template ctRegex(alias pattern, alias flags = [])
Experimental feature.

Compile regular expression using CTFE and generate optimized native machine code for matching it.

Returns:
StaticRegex object for faster matching.

Parameters:
pattern | Regular expression
flags | The attributes (g, i, m and x accepted)

auto match(R, RegEx)(R input, RegEx re);
auto match(R, String)(R input, String re);
Start matching input to regex pattern re, using Thompson NFA matching scheme.

This is the recommended method for matching regular expression.

re parameter can be one of three types:
  • Plain string, in which case it's compiled to bytecode before matching.
  • Regex!char (wchar/dchar) that contains pattern in form of precompiled bytecode.
  • StaticRegex!char (wchar/dchar) that contains pattern in form of specially crafted native code.

Returns:
a RegexMatch object holding engine state after first match.

auto bmatch(R, RegEx)(R input, RegEx re);
auto bmatch(R, String)(R input, String re);
Start matching input to regex pattern re, using traditional backtracking matching scheme.

re parameter can be one of three types:
  • Plain string, in which case it's compiled to bytecode before matching.
  • Regex!char (wchar/dchar) that contains pattern in form of precompiled bytecode.
  • StaticRegex!char (wchar/dchar) that contains pattern in form of specially crafted native code.

Returns:
a RegexMatch object holding engine state after first match.

R replace(alias scheme = match, R, RegEx)(R input, RegEx re, R format);
Construct a new string from input by replacing each match with a string generated from match according to format specifier.

To replace all occurrences use regex with "g" flag, otherwise only the first occurrence gets replaced.

Parameters:
input | string to search
re | compiled regular expression to use
format | format string to generate replacements from

Example:
    // Comify a number
    auto com = regex(r"(?<=\d)(?=(\d\d\d)+\b)","g");
    assert(replace("12000 + 42100 = 54100", com, ",") == "12,000 + 42,100 = 54,100");

The format string can reference parts of match using the following notation.
Format specifier | Replaced by
$& the whole match.
$` part of input preceding the match.
$' part of input following the match.
$$ '$' character.
\c , where c is any character | the character c itself.
\\ '\' character.
$1 .. $99 | submatch number 1 to 99 respectively.
    assert(replace("noon", regex("^n"), "[$&]") == "[n]oon");

R replace(alias fun, R, RegEx, alias scheme = match)(R input, RegEx re);
Search string for matches using regular expression pattern re and pass captures for each match to user-defined functor fun.

To replace all occurrances use regex with "g" flag, otherwise only first occurrence gets replaced.

Returns:
new string with all matches replaced by return values of fun.

Parameters:
s | string to search
re | compiled regular expression
fun | delegate to use

Example:
Capitalize the letters 'a' and 'r':
    string baz(Captures!(string) m)
    {
        return std.string.toUpper(m.hit);
    }
    auto s = replace!(baz)("Strap a rocket engine on a chicken.",
            regex("[ar]", "g"));
    assert(s == "StRAp A Rocket engine on A chicken.");

struct Splitter(Range, alias RegEx = Regex) if (isSomeString!(Range) && isRegexFor!(RegEx, Range));
Range that splits a string using a regular expression as a separator.

Example:
auto s1 = ", abc, de,  fg, hi, ";
assert(equal(splitter(s1, regex(", *")),
    ["", "abc", "de", "fg", "hi", ""]));

Range front();
bool empty();
void popFront();
@property auto save();
Forward range primitives.

Splitter!(Range, RegEx) splitter(Range, RegEx)(Range r, RegEx pat);
A helper function, creates a Splitter on range r separated by regex pat. Captured subexpressions have no effect on the resulting range.

String[] split(String, RegEx)(String input, RegEx rx);
An eager version of splitter that creates an array with splitted slices of input.

class RegexException: object.Exception;
Exception object thrown in case of errors during regex compilation.

this(string msg, string file = __FILE__, size_t line = __LINE__);

Copyright Dmitry Olshansky, 2011 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.signals

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:
A Deeper Look at Signals and Slots
Observer pattern
Wikipedia
Boost Signals
Qt

There has been a great deal of discussion in the D newsgroups over this, and several implementations:

signal slots library
Signals and Slots in D
Dynamic binding -- Qt's Signals and Slots vs Objective-C
Dissecting the SS
about harmonia
Another event handling module
Suggestion: signal/slot mechanism
Signals and slots?
Signals and slots ready for evaluation
Signals & Slots for Walter
Signal/Slot mechanism?
Modern Features?
Delegates vs interfaces
The importance of component programming (properties signals and slots etc)
signals and slots

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.

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/signals.d

template Signal(T1...)
Mixin to create a signal within a class object.

Different signals can be added to a class by naming the mixins.

Example:
import std.signals;
import std.stdio;

class Observer
{   // our slot
    void watch(string msg, int i)
    {
        writefln("Observed msg '%s' and value %s", msg, i);
    }
}

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

void main()
{
    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()
}
which should print:
 Observed msg 'setting new value' and value 4
 Observed msg 'setting new value' and value 6

alias void delegate(T1) slot_t;
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.

void emit(T1 i);
Call each of the connected slots, passing the argument(s) i to them.

void connect(slot_t slot);
Add a slot to the list of slots to be called when emit() is called.

void disconnect(slot_t slot);
Remove a slot from the list of slots to be called when emit() is called.

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.socket

Example:
See /dmd/samples/d/listener.d and /dmd/samples/d/htmlget.d

License:
Boost License 1.0.

Authors:
Christopher E. Miller, David Nadlinger, Vladimir Panteleev

Source:
std/socket.d

class SocketException: object.Exception;
Base exception thrown by std.socket.

deprecated const @property int errorCode();
Deprecated. It will be removed in January 2013. Please use SocketOSException instead.

Provided for compatibility with older code using SocketException.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__);

@property string lastSocketError();
Retrieve the error message for the most recently encountered network error.

class SocketOSException: std.socket.SocketException;
Socket exceptions representing network errors reported by the operating system.

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) errorFormatter = &formatSocketError);

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr(), string function(int) errorFormatter = &formatSocketError);

this(string msg, int err, string function(int) errorFormatter = &formatSocketError, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

class SocketParameterException: std.socket.SocketException;
Socket exceptions representing invalid parameters specified by user code.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__);

class SocketFeatureException: std.socket.SocketException;
Socket exceptions representing attempts to use network capabilities not available on the current system.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__);

bool wouldHaveBlocked();
Return true if the last socket operation failed because the socket was in non-blocking mode and the operation would have blocked.

enum AddressFamily;
The communication domain used to resolve an address.

UNSPEC
Unspecified address family

UNIX
Local communication

INET
Internet Protocol version 4

IPX
Novell IPX

APPLETALK
AppleTalk

INET6
Internet Protocol version 6

enum SocketType;
Communication semantics

STREAM
Sequenced, reliable, two-way communication-based byte streams

DGRAM
Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order

RAW
Raw protocol access

RDM
Reliably-delivered message datagrams

SEQPACKET
Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length

enum ProtocolType;
Protocol

IP
Internet Protocol version 4

ICMP
Internet Control Message Protocol

IGMP
Internet Group Management Protocol

GGP
Gateway to Gateway Protocol

TCP
Transmission Control Protocol

PUP
PARC Universal Packet Protocol

UDP
User Datagram Protocol

IDP
Xerox NS protocol

RAW
Raw IP packets

IPV6
Internet Protocol version 6

class Protocol;
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");

ProtocolType type;
string name;
string[] aliases;
These members are populated when one of the following functions are called successfully:

bool getProtocolByName(in char[] name);
Returns:
false on failure

bool getProtocolByType(ProtocolType type);
Returns:
false on failure

class Service;
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.");

string name;
string[] aliases;
ushort port;
string protocolName;
These members are populated when one of the following functions are called successfully:

bool getServiceByName(in char[] name, in char[] protocolName = null);
bool getServiceByPort(ushort port, in char[] protocolName = null);
If a protocol name is omitted, any protocol will be matched.

Returns:
false on failure.

class HostException: std.socket.SocketOSException;
Class for exceptions thrown from an InternetHost.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr());

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr());

this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

class InternetHost;
InternetHost is a class for resolving IPv4 addresses.

Consider using getAddress, parseAddress and 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");

string name;
string[] aliases;
uint[] addrList;
These members are populated when one of the following functions are called successfully:

bool getHostByName(in char[] name);
Resolve host name.

Returns:
false if unable to resolve.

bool getHostByAddr(uint addr);
Resolve IPv4 address number.

Parameters:
uint addr The IPv4 address to resolve, in host byte order.

Returns:
false if unable to resolve.

bool getHostByAddr(in char[] addr);
Same as previous, but addr is an IPv4 address string in the dotted-decimal form a.b.c.d.

Returns:
false if unable to resolve.

struct AddressInfo;
Holds information about a socket address retrieved by getAddressInfo.

AddressFamily family;
Address family

SocketType type;
Socket type

ProtocolType protocol;
Protocol

Address address;
Socket address

string canonicalName;
Canonical name, when AddressInfoFlags.CANONNAME is used.

enum AddressInfoFlags;
Specifies option flags for getAddressInfo.

PASSIVE
The resulting addresses will be used in a call to Socket.bind.

CANONNAME
The canonical name is returned in canonicalName member in the first AddressInfo.

NUMERICHOST
The node parameter passed to getAddressInfo must be a numeric string. This will suppress any potentially lengthy network host address lookups.

AddressInfo[] getAddressInfo(T...)(in char[] node, T options);
Provides protocol-independent translation from host names to socket addresses. If advanced functionality is not required, consider using getAddress for compatibility with older systems.

Returns:
Array with one AddressInfo per socket address.

Throws:
SocketOSException on failure, or SocketFeatureException if this functionality is not available on the current system.

Parameters:
node string containing host name or numeric address
options optional additional parameters, identified by type:
  • string - service name or port number
  • AddressInfoFlags - option flags
  • AddressFamily - address family to filter by
  • SocketType - socket type to filter by
  • 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);

Address[] getAddress(in char[] hostname, in char[] service = null);
Address[] getAddress(in char[] hostname, ushort port);
Provides protocol-independent translation from host names to socket addresses. Uses getAddressInfo if the current system supports it, and InternetHost otherwise.

Returns:
Array with one Address instance per socket address.

Throws:
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 parseAddress(in char[] hostaddr, in char[] service = null);
Address parseAddress(in char[] hostaddr, ushort port);
Provides protocol-independent parsing of network addresses. Does not attempt name resolution. Uses getAddressInfo with AddressInfoFlags.NUMERICHOST if the current system supports it, and InternetAddress otherwise.

Returns:
An Address instance representing specified address.

Throws:
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);
 }

class AddressException: std.socket.SocketOSException;
Class for exceptions thrown from an Address.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr());

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr());

this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

abstract class Address;
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 @property sockaddr* name();
abstract const @property const(sockaddr)* name();
Returns pointer to underlying sockaddr structure.

abstract const @property socklen_t nameLen();
Returns actual size of underlying sockaddr structure.

const @property AddressFamily addressFamily();
Family of this address.

const string toAddrString();
Attempts to retrieve the host address as a human-readable string.

Throws:
AddressException on failure, or SocketFeatureException if address retrieval for this address family is not available on the current system.

const string toHostNameString();
Attempts to retrieve the host name as a fully qualified domain name.

Returns:
The FQDN corresponding to this Address, or null if the host name did not resolve.

Throws:
AddressException on error, or SocketFeatureException if host name lookup for this address family is not available on the current system.

const string toPortString();
Attempts to retrieve the numeric port number as a string.

Throws:
AddressException on failure, or SocketFeatureException if port number retrieval for this address family is not available on the current system.

const string toServiceNameString();
Attempts to retrieve the service name as a string.

Throws:
AddressException on failure, or SocketFeatureException if service name lookup for this address family is not available on the current system.

const string toString();
Human readable string representing this address.

class UnknownAddress: std.socket.Address;
UnknownAddress encapsulates an unknown socket address.

class UnknownAddressReference: std.socket.Address;
UnknownAddressReference encapsulates a reference to an arbitrary socket address.

this(sockaddr* sa, socklen_t len);
Constructs an Address with a reference to the specified sockaddr.

this(const(sockaddr)* sa, socklen_t len);
Constructs an Address with a copy of the specified sockaddr.

class InternetAddress: std.socket.Address;
InternetAddress encapsulates an IPv4 (Internet Protocol version 4) socket address.

Consider using getAddress, parseAddress and Address methods instead of using this class directly.

uint ADDR_ANY;
Any IPv4 host address.

uint ADDR_NONE;
An invalid IPv4 host address.

ushort PORT_ANY;
Any IPv4 port number.

const @property ushort port();
Returns the IPv4 port number (in host byte order).

const @property uint addr();
Returns the IPv4 address number (in host byte order).

this(in char[] addr, ushort port);
Construct a new InternetAddress.

Parameters:
char[] addr | an IPv4 address string in the dotted-decimal form a.b.c.d, or a host name which will be resolved using an InternetHost object.
ushort port | port number, may be PORT_ANY.

this(uint addr, ushort port);
this(ushort port);
Construct a new InternetAddress.

Parameters:
uint addr | (optional) an IPv4 address in host byte order, may be ADDR_ANY.
ushort port | port number, may be PORT_ANY.

const string toAddrString();
Human readable string representing the IPv4 address in dotted-decimal form.

const string toPortString();
Human readable string representing the IPv4 port.

const string toHostNameString();
Attempts to retrieve the host name as a fully qualified domain name.

Returns:
The FQDN corresponding to this InternetAddress, or null if the host name did not resolve.

Throws:
AddressException on error.

static uint parse(in char[] addr);
Parse an IPv4 address string in the dotted-decimal form a.b.c.d and return the number.

Returns:
If the string is not a legitimate IPv4 address, ADDR_NONE is returned.

static string addrToString(uint addr);
Convert an IPv4 address number in host byte order to a human readable string representing the IPv4 address in dotted-decimal form.

class Internet6Address: std.socket.Address;
Internet6Address encapsulates an IPv6 (Internet Protocol version 6) socket address.

Consider using getAddress, parseAddress and Address methods instead of using this class directly.

static @property ref const(ubyte)[16u] ADDR_ANY();
Any IPv6 host address.

ushort PORT_ANY;
Any IPv6 port number.

const @property ushort port();
Returns the IPv6 port number.

const @property ubyte[16u] addr();
Returns the IPv6 address.

this(in char[] node, in char[] service = null);
Construct a new Internet6Address.

Parameters:
char[] node | an IPv6 host address string in the form described in RFC 2373, or a host name which will be resolved using getAddressInfo.
port | (optional) service name or port number.

this(in char[] node, ushort port);
Construct a new Internet6Address.

Parameters:
addr | an IPv6 host address string in the form described in RFC 2373, or a host name which will be resolved using getAddressInfo.
ushort port | port number, may be PORT_ANY.

this(ubyte[16] addr, ushort port);
this(ushort port);
Construct a new Internet6Address.

Parameters:
ubyte[16] addr | (optional) an IPv6 host address in host byte order, or ADDR_ANY.
ushort port | port number, may be PORT_ANY.

static ubyte[16u] parse(in char[] addr);
Parse an IPv6 host address string as described in RFC 2373, and return the address.

Throws:
SocketException on error.

abstract class UnixAddress: std.socket.Address;
UnixAddress encapsulates an address for a Unix domain socket (AF_UNIX). Available only on supported systems.

this(in char[] path);
Construct a new UnixAddress from the specified path.

const @property string path();
const string toString();
Get the underlying path.

class SocketAcceptException: std.socket.SocketOSException;
Class for exceptions thrown by Socket.accept.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr());

this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr());

this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null);

enum SocketShutdown;
How a socket is shutdown:

RECEIVE
socket receives are disallowed

SEND
socket sends are disallowed

BOTH
both RECEIVE and SEND

enum SocketFlags;
Flags may be OR'ed together:

NONE
no flags specified

OOB
out-of-band stream data

PEEK
peek at incoming data without removing it from the queue, only for receiving

DONTROUTE
data should not be subject to routing; this flag may be ignored. Only for sending

struct TimeVal;
Duration timeout value.

tv_sec_t seconds;
Number of seconds.

tv_usec_t microseconds;
Number of additional microseconds.

deprecated alias TimeVal timeval;
Deprecated. It will be removed in January 2013. Please use TimeVal instead.

class SocketSet;
A collection of sockets for use with Socket.select.

SocketSet allows specifying the capacity of the underlying fd_set, however users should be aware that the exact meaning of this value varies depending on the current platform:
  • On POSIX, fd_set is a bit array of file descriptors. The SocketSet capacity specifies the highest file descriptor which can be stored in the set.
  • on Windows, fd_set is an array of socket handles. Capacity indicates the actual number of sockets that can be stored in the set.

this(uint max);
Set the capacity of this SocketSet. The exact meaning of the max parameter varies from platform to platform.

Throws:
SocketParameterException if max exceeds this platform's maximum socket set size.

this();
Uses the default capacity for the system.

void reset();
Reset the SocketSet so that there are 0 Sockets in the collection.

void add(Socket s);
Add a Socket to the collection.

Throws:
SocketParameterException if the capacity of this SocketSet has been exceeded.

void remove(Socket s);
Remove this Socket from the collection.

const int isSet(Socket s);
Returns nonzero if this Socket is in the collection.

const @property uint max();
Return the capacity of this SocketSet. The exact meaning of the return value varies from platform to platform.

enum SocketOptionLevel;
The level at which a socket option is defined:

SOCKET
Socket level

IP
Internet Protocol version 4 level

ICMP
Internet Control Message Protocol level

IGMP
Internet Group Management Protocol level

GGP
Gateway to Gateway Protocol level

TCP
Transmission Control Protocol level

PUP
PARC Universal Packet Protocol level

UDP
User Datagram Protocol level

IDP
Xerox NS protocol level

RAW
Raw IP packet level

IPV6
Internet Protocol version 6 level

struct Linger;
Linger information for use with SocketOption.LINGER.

l_onoff_t on;
Nonzero for on.

l_linger_t time;
Linger time.

deprecated alias Linger linger;
Deprecated. It will be removed in January 2013. Please use Linger instead.

enum SocketOption;
Specifies a socket option:

DEBUG
Record debugging information

BROADCAST
Allow transmission of broadcast messages

REUSEADDR
Allow local reuse of address

LINGER
Linger on close if unsent data is present

OOBINLINE
Receive out-of-band data in band

SNDBUF
Send buffer size

RCVBUF
Receive buffer size

DONTROUTE
Do not route

SNDTIMEO
Send timeout

RCVTIMEO
Receive timeout

ERROR
Retrieve and clear error status

KEEPALIVE
Enable keep-alive packets

ACCEPTCONN
Listen

RCVLOWAT
Minimum number of input bytes to process

SNDLOWAT
Minimum number of output bytes to process

TYPE
Socket type

TCP_NODELAY
Disable the Nagle algorithm for send coalescing

IPV6_UNICAST_HOPS
IP unicast hop limit

IPV6_MULTICAST_IF
IP multicast interface

IPV6_MULTICAST_LOOP
IP multicast loopback

IPV6_MULTICAST_HOPS
IP multicast hops

IPV6_JOIN_GROUP
Add an IP group membership

IPV6_LEAVE_GROUP
Drop an IP group membership

IPV6_V6ONLY
Treat wildcard bind as AF_INET6-only

class Socket;
Socket is a class that creates a network communication endpoint using the Berkeley sockets interface.

this(AddressFamily af, SocketType type, ProtocolType protocol);
this(AddressFamily af, SocketType type);
this(AddressFamily af, SocketType type, in char[] protocolName);
Create a blocking socket. If a single protocol type exists to support this socket type within the address family, the ProtocolType may be omitted.

this(in AddressInfo info);
Create a blocking socket using the parameters from the specified AddressInfo structure.

this(socket_t sock, AddressFamily af);
Use an existing socket handle.

const @property socket_t handle();
Get underlying socket handle.

const @property bool blocking();
@property void blocking(bool byes);
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 AddressFamily addressFamily();
Get the socket's address family.

const @property bool isAlive();
Property that indicates if this is a valid, alive socket.

void bind(Address addr);
Associate a local address with this socket.

void connect(Address to);
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 listen(int backlog);
Listen for an incoming connection. bind must be called before you can listen. The backlog is a request of how many pending incoming connections are queued until accepted.

protected Socket accepting();
Called by accept when a new 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 Socket's handle must not be set; Socket has a protected constructor this() to use in this situation.

Socket accept();
Accept an incoming connection. If the socket is blocking, accept waits for a connection request. Throws SocketAcceptException if unable to accept. See accepting for use with derived classes.

void shutdown(SocketShutdown how);
Disables sends and/or receives.

void close();
Immediately drop any connections and release socket resources. Calling shutdown before close is recommended for connection-oriented sockets. The Socket object is no longer usable after close.

static @property string hostName();
Returns the local machine's host name.

@property Address remoteAddress();
Remote endpoint Address.

@property Address localAddress();
Local endpoint Address.

int ERROR;
Send or receive error code. See wouldHaveBlocked, lastSocketError and Socket.getErrorText for obtaining more information about the error.

ptrdiff_t send(const(void)[] buf, SocketFlags flags);
ptrdiff_t send(const(void)[] buf);
Send data on the connection. If the socket is blocking and there is no buffer space left, send waits.

Returns:
The number of bytes actually sent, or Socket.ERROR on failure.

ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to);
ptrdiff_t sendTo(const(void)[] buf, Address to);
ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags);
ptrdiff_t sendTo(const(void)[] buf);
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, sendTo waits.

Returns:
The number of bytes actually sent, or Socket.ERROR on failure.

ptrdiff_t receive(void[] buf, SocketFlags flags);
ptrdiff_t receive(void[] buf);
Receive data on the connection. If the socket is blocking, receive waits until there is data to be received.

Returns:
The number of bytes actually received, 0 if the remote side has closed the connection, or Socket.ERROR on failure.

ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from);
ptrdiff_t receiveFrom(void[] buf, ref Address from);
ptrdiff_t receiveFrom(void[] buf, SocketFlags flags);
ptrdiff_t receiveFrom(void[] buf);
Receive data and get the remote endpoint Address. If the socket is blocking, receiveFrom waits until there is data to be received.

Returns:
The number of bytes actually received, 0 if the remote side has closed the connection, or Socket.ERROR on failure.

int getOption(SocketOptionLevel level, SocketOption option, void[] result);
Get a socket option.

Returns:
The number of bytes written to result.

int getOption(SocketOptionLevel level, SocketOption option, out int32_t result);
Common case of getting integer and boolean options.

int getOption(SocketOptionLevel level, SocketOption option, out Linger result);
Get the linger option.

void getOption(SocketOptionLevel level, SocketOption option, out Duration result);
Get a timeout (duration) option.

void setOption(SocketOptionLevel level, SocketOption option, int32_t value);
Common case for setting integer and boolean options.

void setOption(SocketOptionLevel level, SocketOption option, Linger value);
Set the linger option.

void setOption(SocketOptionLevel level, SocketOption option, Duration value);
Sets a timeout (duration) option, i.e. SocketOption.SNDTIMEO or 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. 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.

Parameters:
Duration value The timeout duration to set. Must not be negative.

Throws:
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);

string getErrorText();
Get a text description of this socket's error status, and clear the socket's error status.

void setKeepAlive(int time, int interval);
Enables TCP keep-alive with the specified parameters.

Parameters:
int time | Number of seconds with no activity until the first keep-alive packet is sent.
int interval | Number of seconds between when successive keep-alive packets are sent if no acknowledgement is received.

Throws:
SocketOSException if setting the options fails, or SocketFeatureException if setting keep-alive parameters is unsupported on the current platform.

static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, Duration timeout);
static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError);
static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeVal* timeout);
Wait for a socket to change status. A wait timeout of or (D TimeVal, may be specified; if a timeout is not specified or the TimeVal is null, the maximum timeout is used. The TimeVal timeout has an unspecified value when select returns.

Returns:
The number of sockets with status changes, 0 on timeout, or -1 on interruption. If the return value is greater than 0, the 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.

protected Address createAddress();
Returns a new Address object for the current address family. Can be overridden to support other addresses.

class TcpSocket: std.socket.Socket;
TcpSocket is a shortcut class for a TCP Socket.

this(AddressFamily family);
Constructs a blocking TCP Socket.

this();
Constructs a blocking IPv4 TCP Socket.

this(Address connectTo);
Constructs a blocking TCP Socket and connects to an Address.

class UdpSocket: std.socket.Socket;
UdpSocket is a shortcut class for a UDP Socket.

this(AddressFamily family);
Constructs a blocking UDP Socket.

this();
Constructs a blocking IPv4 UDP Socket.

Socket[2u] socketPair();
Creates a pair of connected sockets.

The two sockets are indistinguishable.

Throws:
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);

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.socketstream

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.

SocketStream is a stream for a blocking, connected Socket.

Example:
See /dmd/samples/d/htmlget.d

Authors:
Christopher E. Miller

References:
std.stream

Source:
std/socketstream.d

class SocketStream: std.stream.Stream;
SocketStream is a stream for a blocking, connected Socket.

this(Socket sock, FileMode mode);
Constructs a SocketStream with the specified Socket and FileMode flags.

this(Socket sock);
Uses mode FileMode.In | FileMode.Out.

Socket socket();
Property to get the Socket that is being streamed.

size_t readBlock(void* _buffer, size_t size);
Attempts to read the entire block, waiting if necessary.

size_t writeBlock(const void* _buffer, size_t size);
Attempts to write the entire block, waiting if necessary.

ulong seek(long offset, SeekPos whence);
Socket streams do not support seeking. This disabled method throws a SeekException.

string toString();
Does not return the entire stream because that would require the remote connection to be closed.

void close();
Close the Socket.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.stdio

Standard I/O functions that extend std.c.stdio. std.c.stdio is publically imported when importing std.stdio.

Source:
std/stdio.d

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Alex Rønne Petersen

struct File;
Encapsulates a FILE*. Generally D does not attempt to provide thin wrappers over equivalent functions in the C standard library, but manipulating FILE* values directly is unsafe and error-prone in many ways. The File type ensures safe manipulation, automatic file closing, and a lot of convenience.

The underlying FILE* handle is maintained in a reference-counted manner, such that as soon as the last File variable bound to a given FILE* goes out of scope, the underlying 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 FILE* is closed.
}

% rdmd test.d Jimmy
% cat test.txt
Hello, Jimmy!
% _

this(string name, in char[] stdioOpenmode = "rb");
Constructor taking the name of the file to open and the open mode (with the same semantics as in the C standard library fopen function). Throws an exception if the file could not be opened.

Copying one File object to another results in the two File objects referring to the same underlying file.

The destructor automatically closes the file as soon as no File object refers to it anymore.

void opAssign(File rhs);
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 open(string name, in char[] stdioOpenmode = "rb");
First calls detach (throwing on failure), and then attempts to open file name with mode stdioOpenmode. The mode has the same semantics as in the C standard library fopen function. Throws exception in case of error.

const pure nothrow @property bool isOpen();
Returns true if the file is opened.

const pure @property bool eof();
Returns true if the file is at end (see feof). The file must be opened, otherwise an exception is thrown.

const pure nothrow @property string name();
Returns the name of the last opened file, if any. If a File was created with tmpfile and wrapFile it has no name.

const pure nothrow @property bool error();
If the file is not opened, returns false. Otherwise, returns ferror for the file handle.

void detach();
Detaches from the underlying file. If the sole owner, calls close and throws if that fails.

void close();
If the file was unopened, succeeds vacuously. Otherwise closes the file (by calling fclose), throwing on error. Even if an exception is thrown, afterwards the File object is empty. This is different from detach in that it always closes the file; consequently, all other File objects referring to the same handle will see a closed file henceforth.

pure nothrow void clearerr();
If the file is not opened, succeeds vacuously. Otherwise, returns clearerr for the file handle.

void flush();
If the file is not opened, throws an exception. Otherwise, calls fflush for the file handle and throws on error.

T[] rawRead(T)(T[] buffer);
If the file is not opened, throws an exception. Otherwise, calls fread for the file handle and throws on error. 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 buffer containing the data that was actually read. This will be shorter than buffer if EOF was reached before the buffer could be filled.

rawRead always reads in binary mode on Windows.

void rawWrite(T)(in T[] buffer);
If the file is not opened, throws an exception. Otherwise, calls fwrite for the file handle and throws on error. 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.

rawWrite always writes in binary mode on Windows.

void seek(long offset, int origin = SEEK_SET);
If the file is not opened, throws an exception. Otherwise, calls fseek for the file handle. Throws on error.

const @property ulong tell();
If the file is not opened, throws an exception. Otherwise, calls ftell for the managed file handle. Throws on error.

void rewind();
If the file is not opened, throws an exception. Otherwise, calls rewind for the file handle. Throws on error.

void setvbuf(size_t size, int mode = _IOFBF);
If the file is not opened, throws an exception. Otherwise, calls setvbuf for the file handle.

void setvbuf(void[] buf, int mode = _IOFBF);
If the file is not opened, throws an exception. Otherwise, calls setvbuf for the file handle.

void write(S...)(S args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file.

void writeln(S...)(S args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file, followed by a newline.

void writef(Char, A...)(in Char[] fmt, A args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file, according to the format in the first argument.

void writefln(Char, A...)(in Char[] fmt, A args);
Same as writef, plus adds a newline.

S readln(S = string)(dchar terminator = '\x0a');
size_t readln(C)(ref C[] buf, dchar terminator = '\x0a');
size_t readln(C, R)(ref C[] buf, R terminator);
Read line from stream fp and write it to buf[], including terminating character.

This is often faster than File.readln(dchar) because the buffer is reused each call. Note that reusing the buffer means that the previous contents of it has to be copied if needed.

Parameters:
fp | input stream
buf | buffer used to store the resulting line data. buf is resized as necessary.

Returns:
0 for end of file, otherwise number of characters read

Throws:
StdioException on I/O error, or UnicodeException on Unicode conversion error.

Example:
// Reads stdin and writes it to stdout.
import std.stdio;

int main()
{
    char[] buf;
    while (stdin.readln(buf))
        write(buf);
    return 0;
}

This method is more efficient than the one in the previous example because stdin.readln(buf) reuses (if possible) memory allocated by buf, whereas buf = stdin.readln() makes a new memory allocation with every line.

uint readf(Data...)(in char[] format, Data data);
Read data from the file according to the specified format specifier using std.format.formattedRead.

static File tmpfile();
Returns a temporary file by calling tmpfile. Note that the created file has no name.

static File wrapFile(shared(_iobuf)* f);
Unsafe function that wraps an existing FILE*. The resulting File never takes the initiative in closing the file. Note that the created file has no name

pure shared(_iobuf)* getFP();
Returns the FILE* corresponding to this object.

const int fileno();
Returns the file number corresponding to this object.

struct ByLine(Char, Terminator);
Range that reads one line at a time. ditto

const bool empty();
Char[] front();
void popFront();
Range primitive implementations.

ByLine!(Char, Terminator) byLine(Terminator = char, Char = char)(KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\x0a');
Convenience function that returns the LinesReader corresponding to this file.

struct ByChunk;
Range that reads a chunk at a time.

const @property bool empty();
nothrow @property ubyte[] front();
void popFront();
Range primitive operations.

ByChunk byChunk(size_t chunkSize);
Iterates through a file a chunk at a time by using foreach.

Example:
void main()
{
  foreach (ubyte[] buffer; stdin.byChunk(4096))
  {
    ... use buffer ...
  }
}

The content of buffer is reused across calls. In the example above, buffer.length is 4096 for all iterations, except for the last one, in which case buffer.length may be less than 4096 (but always greater than zero).

In case of an I/O error, an StdioException is thrown.

struct LockingTextWriter;
Range that locks the file and allows fast writing to it.

void put(A)(A writeme);
void put(C)(C c);
Range primitive implementations.

@property LockingTextWriter lockingTextWriter();
Convenience function.

@property ulong size();
Get the size of the file, ulong.max if file is not searchable, but still throws if an actual error occurs.

template isFileHandle(T)
Indicates whether T is a file handle of some kind.

alias isFileHandle(T) isStreamingDevice;
Scheduled for deprecation in January 2013. Please use isFileHandle instead.

void write(T...)(T args);
For each argument arg in args, format the argument (as per to!(string)(arg)) and write the resulting string to args[0]. A call without any arguments will fail to compile.

Throws:
In case of an I/O error, throws an StdioException.

void writeln(T...)(T args);
Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

void writef(T...)(T args);
If the first argument args[0] is a FILE*, use the format specifier in args[1] to control the formatting of args[2..$], and write the resulting string to args[0]. If arg[0] is not a FILE*, the call is equivalent to writef(stdout, args).

IMPORTANT:
New behavior starting with D 2.006: unlike previous versions, writef (and also writefln) only scans its first string argument for format specifiers, but not subsequent string arguments. This decision was made because the old behavior made it unduly hard to simply print string variables that occasionally embedded percent signs.

Also new starting with 2.006 is support for positional parameters with POSIX syntax.

Example:
writef("Date: %2$s %1$s", "October", 5); // "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 popFront parameter after the largest positional parameter already used.

New starting with 2.008: raw format specifiers. Using the "%r" specifier makes writef simply write the binary representation of the argument. Use "%-r" to write numbers in little endian format, "%+r" to write numbers in big endian format, and "%r" to write numbers in platform-native format.

void writefln(T...)(T args);
Equivalent to writef(args, '\n').

uint readf(A...)(in char[] format, A args);
Read data from stdin according to the specified format specifier using std.format.formattedRead.

string readln(dchar terminator = '\x0a');
size_t readln(ref char[] buf, dchar terminator = '\x0a');
Read line from stream fp.

Returns:
null for end of file, char[] for line read from fp, including terminating character

Parameters:

Throws:
StdioException on error

Example:
Reads stdin and writes it to stdout.
import std.stdio;

int main()
{
    char[] buf;
    while ((buf = readln()) != null)
        write(buf);
    return 0;
}

struct lines;
Iterates through the lines of a file by using foreach.

Example:
void main()
{
  foreach (string line; lines(stdin))
  {
    ... use line ...
  }
}
The line terminator ('\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 line, and the behavior of lines changes accordingly:

  1. If line has type string, wstring, or dstring, a new string of the respective type is allocated every read.
  2. If line has type char[], wchar[], dchar[], the line's content will be reused (overwritten) across reads.
  3. If line has type immutable(ubyte)[], the behavior is similar to case (1), except that no UTF checking is attempted upon input.
  4. If line has type 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. ulong or 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 StdioException is thrown.

struct chunks;
Iterates through a file a chunk at a time by using foreach.

Example:
void main()
{
  foreach (ubyte[] buffer; chunks(stdin, 4096))
  {
    ... use buffer ...
  }
}

The content of buffer is reused across calls. In the example above, buffer.length is 4096 for all iterations, except for the last one, in which case buffer.length may be less than 4096 (but always greater than zero).

In case of an I/O error, an StdioException is thrown.

class StdioException: object.Exception;
Thrown if I/O errors happen.

uint errno;
Operating system error code.

this(string message, uint e = .errno);
Initialize with a message and an error code.

static void opCall(string msg);
static void opCall();
Convenience functions that throw an StdioException.

File stdin;
The standard input stream.

File stdout;
The standard output stream.

File stderr;
The standard error stream.

Copyright Digital Mars 2007-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.cstream

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.

The std.cstream module bridges std.c.stdio (or std.stdio) and std.stream. Both std.c.stdio and std.stream are publicly imported by std.cstream.

License:
Boost License 1.0.

Authors:
Ben Hinkle

Source:
std/cstream.d

class CFile: std.stream.Stream;
A Stream wrapper for a C file of type FILE*.

this(FILE* cfile, FileMode mode, bool seekable = false);
Create the stream wrapper for the given C file.

Parameters:
FileMode mode | a bitwise combination of FileMode.In for a readable file and FileMode.Out for a writeable file.
bool seekable | indicates if the stream should be seekable.

@property shared(_iobuf)* file();
@property void file(shared(_iobuf)* cfile);
Property to get or set the underlying file for this stream. Setting the file marks the stream as open.

void flush();
void close();
bool eof();
char getc();
char ungetc(char c);
size_t readBlock(void* buffer, size_t size);
size_t writeBlock(const void* buffer, size_t size);
ulong seek(long offset, SeekPos rel);
void writeLine(const(char)[] s);
void writeLineW(const(wchar)[] s);
Overrides of the Stream methods to call the underlying FILE* C functions.

CFile din;
CFile wrapper of std.c.stdio.stdin (not seekable).

CFile dout;
CFile wrapper of std.c.stdio.stdout (not seekable).

CFile derr;
CFile wrapper of std.c.stdio.stderr (not seekable).

Copyright Ben Hinkle 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.stream

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.

Source:
std/stream.d

class StreamException: object.Exception;
A base class for stream exceptions.

this(string msg);
Construct a StreamException with given error message.

class ReadException: std.stream.StreamException;
Thrown when unable to read data from Stream.

this(string msg);
Construct a ReadException with given error message.

class WriteException: std.stream.StreamException;
Thrown when unable to write data to Stream.

this(string msg);
Construct a WriteException with given error message.

class SeekException: std.stream.StreamException;
Thrown when unable to move Stream pointer.

this(string msg);
Construct a SeekException with given error message.

abstract interface InputStream;
InputStream is the interface for readable streams.

abstract void readExact(void* buffer, size_t size);
Read exactly size bytes into the buffer.

Throws a ReadException if it is not correct.

abstract size_t read(ubyte[] buffer);
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.

abstract void read(out byte x);
abstract void read(out ubyte x);
abstract void read(out short x);
abstract void read(out ushort x);
abstract void read(out int x);
abstract void read(out uint x);
abstract void read(out long x);
abstract void read(out ulong x);
abstract void read(out float x);
abstract void read(out double x);
abstract void read(out real x);
abstract void read(out ifloat x);
abstract void read(out idouble x);
abstract void read(out ireal x);
abstract void read(out cfloat x);
abstract void read(out cdouble x);
abstract void read(out creal x);
abstract void read(out char x);
abstract void read(out wchar x);
abstract void read(out dchar x);
abstract void read(out char[] s);
abstract void read(out wchar[] s);
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.

abstract char[] readLine();
abstract char[] readLine(char[] result);
abstract wchar[] readLineW();
abstract wchar[] readLineW(wchar[] result);
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.

abstract int opApply(scope int delegate(ref char[] line) dg);
abstract int opApply(scope int delegate(ref ulong n, ref char[] line) dg);
abstract int opApply(scope int delegate(ref wchar[] line) dg);
abstract int opApply(scope int delegate(ref ulong n, ref wchar[] line) dg);
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();

abstract char[] readString(size_t length);
Read a string of the given length, throwing ReadException if there was a problem.

abstract wchar[] readStringW(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.

abstract char getc();
abstract wchar getcw();
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.

abstract char ungetc(char c);
abstract wchar ungetcw(wchar c);
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().

abstract int vreadf(TypeInfo[] arguments, void* args);
abstract int readf(...);
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);

abstract @property size_t available();
Retrieve the number of bytes available for immediate reading.

abstract @property bool eof();
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.

abstract @property bool isOpen();
Return true if the stream is currently open.

abstract interface OutputStream;
Interface for writable streams.

abstract void writeExact(const void* buffer, size_t size);
Write exactly size bytes from buffer, or throw a WriteException if that could not be done.

abstract size_t write(const(ubyte)[] buffer);
Write as much of the buffer as possible, returning the number of bytes written.

abstract void write(byte x);
abstract void write(ubyte x);
abstract void write(short x);
abstract void write(ushort x);
abstract void write(int x);
abstract void write(uint x);
abstract void write(long x);
abstract void write(ulong x);
abstract void write(float x);
abstract void write(double x);
abstract void write(real x);
abstract void write(ifloat x);
abstract void write(idouble x);
abstract void write(ireal x);
abstract void write(cfloat x);
abstract void write(cdouble x);
abstract void write(creal x);
abstract void write(char x);
abstract void write(wchar x);
abstract void write(dchar x);
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.

abstract void write(const(char)[] s);
abstract void write(const(wchar)[] s);
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.

abstract void writeLine(const(char)[] s);
Write a line of text, appending the line with an operating-system-specific line ending.

Throws WriteException on error.

abstract void writeLineW(const(wchar)[] 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.

abstract void writeString(const(char)[] s);
Write a string of text.

Throws WriteException if it could not be fully written.

abstract void writeStringW(const(wchar)[] s);
Write a string of text.

The format is implementation-specific. Throws WriteException if it could not be fully written.

abstract size_t vprintf(const(char)[] format, va_list args);
abstract size_t printf(const(char)[] format, ...);
Print a formatted string into the stream using printf-style syntax, returning the number of bytes written.

abstract OutputStream writef(...);
abstract OutputStream writefln(...);
abstract OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline = false);
Print a formatted string into the stream using writef-style syntax.

References:
std.format.

Returns:
self to chain with other stream commands like flush.

abstract void flush();
Flush pending output if appropriate.

abstract void close();
Close the stream, flushing output if appropriate.

abstract @property bool isOpen();
Return true if the stream is currently open.

abstract class Stream: std.stream.InputStream, std.stream.OutputStream;
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

bool readable;
Indicates whether this stream can be read from.

bool writeable;
Indicates whether this stream can be written to.

bool seekable;
Indicates whether this stream can be seeked within.

protected bool isopen;
Indicates whether this stream is open.

protected bool readEOF;
Indicates whether this stream is at eof after the last read attempt.

protected bool prevCr;
For a non-seekable stream indicates that the last readLine or readLineW ended on a '\r' character.

abstract size_t readBlock(void* buffer, size_t size);
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 writeBlock(const void* buffer, size_t size);
Write up to size bytes from buffer in the stream, returning the actual number of bytes that were written.

void copyFrom(Stream s);
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, ulong count);
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.

abstract ulong seek(long offset, SeekPos whence);
Change the current position of the stream. whence is either SeekPos.Set, in which case the offset is an absolute index from the beginning of the stream, SeekPos.Current, in which case the offset is a delta from the current position, or SeekPos.End, in which case the offset is a delta from the end of the stream (negative or zero offsets only make sense in that case). This returns the new file position.

ulong seekSet(long offset);
ulong seekCur(long offset);
ulong seekEnd(long offset);
Aliases for their normal seek counterparts.

@property void position(ulong pos);
Sets file position. Equivalent to calling seek(pos, SeekPos.Set).

@property ulong position();
Returns current file position. Equivalent to seek(0, SeekPos.Current).

@property ulong size();
Retrieve the size of the stream in bytes. The stream must be seekable or a SeekException is thrown.

string toString();
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.

nothrow @trusted size_t toHash();
Get a hash of the stream by reading each byte and using it in a CRC-32 checksum.

class FilterStream: std.stream.Stream;
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.

bool nestClose;
Property indicating when this stream closes to close the source stream as well. Defaults to true.

this(Stream source);
Construct a FilterStream for the given source.

final Stream source();
Get the current source stream.

void source(Stream 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 resetSource();
Indicates the source stream changed state and that this stream should reset any readable, writeable, seekable, isopen and buffering flags.

class BufferedStream: std.stream.FilterStream;
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.

this(Stream source, size_t bufferSize = DefaultBufferSize);
Create a buffered stream for the stream source with the buffer size bufferSize.

class StreamFileException: std.stream.StreamException;
An exception for File errors.

this(string msg);
Construct a StreamFileException with given error message.

class OpenException: std.stream.StreamFileException;
An exception for errors during File.open.

this(string msg);
Construct an OpenFileException with given error message.

class File: std.stream.Stream;
This subclass is for unbuffered file system streams.

this(string filename, FileMode mode = FileMode.In);
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.

void open(string filename, FileMode mode = (FileMode).In);
Open a file for the stream, in an identical manner to the constructors. If an error occurs an OpenException is thrown.

void create(string filename);
void create(string filename, FileMode mode);
Create a file for writing.

void close();
Close the current file if it is open; otherwise it does nothing.

@property size_t available();
For a seekable file returns the difference of the size and position and otherwise returns 0.

class BufferedFile: std.stream.BufferedStream;
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.

this();
opens file for reading

this(string filename, FileMode mode = FileMode.In, size_t bufferSize = DefaultBufferSize);
opens file in requested mode and buffer size

this(File file, size_t bufferSize = DefaultBufferSize);
opens file for reading with requested buffer size

this(HANDLE hFile, FileMode mode, size_t buffersize);
opens existing handle; use with care!

void open(string filename, FileMode mode = (FileMode).In);
opens file in requested mode

void create(string filename, FileMode mode = (FileMode).OutNew);
creates file in requested mode

enum BOM;
UTF byte-order-mark signatures

UTF8
UTF-8

UTF16LE
UTF-16 Little Endian

UTF16BE
UTF-16 Big Endian

UTF32LE
UTF-32 Little Endian

UTF32BE
UTF-32 Big Endian

class EndianStream: std.stream.FilterStream;
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.

Endian endian;
Endianness property of the source stream.

this(Stream source, Endian end = std.system.endian);
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.

int readBOM(int ungetCharSize = 1);
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.

final void fixBO(const(void)* buffer, size_t size);
Correct the byte order of buffer to match native endianness. size must be even.

final void fixBlockBO(void* buffer, uint size, size_t repeat);
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.

void writeBOM(BOM b);
Write the specified BOM b to the source stream.

class TArrayStream(Buffer): Stream;
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.

this(Buffer buf);
Create the stream for the the buffer buf. Non-copying.

ubyte[] data();
Get the current memory data in total.

class MemoryStream: std.stream.TArrayStream!(ubyte[]).TArrayStream;
This subclass reads and constructs an array of bytes in memory.

this();
Create the output buffer and setup for reading, writing, and seeking.

this(ubyte[] buf);
this(byte[] buf);
this(char[] buf);
Create the output buffer and setup for reading, writing, and seeking. Load it with specific input data.

void reserve(size_t count);
Ensure the stream can hold count bytes.

class MmFileStream: std.stream.TArrayStream!(MmFile).TArrayStream;
This subclass wraps a memory-mapped file with the stream API. See std.mmfile module.

this(MmFile file);
Create stream wrapper for file.

class SliceStream: std.stream.FilterStream;
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.

this(Stream s, ulong low);
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, ulong high);
Indicate the high index as well.

Attempting to read or write past the high index results in the end being clipped off.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.string

String handling functions. Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The *string types are preferable because they don't exhibit undesired aliasing, thus making code more robust.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, and Jonathan M Davis

Source:
std/string.d

class StringException: object.Exception;
Exception thrown on errors in std.string functions.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);
Parameters:
string msg | The message for the exception.
string file | The file where the exception occurred.
size_t line | The line number where the exception occurred.
Throwable next | The previous exception in the chain of exceptions, if any.

int icmp(alias pred = "a < b", S1, S2)(S1 s1, S2 s2);
Compares two ranges of characters lexicographically. The comparison is case insensitive. Use XREF algorithm, cmp for a case sensitive comparison. icmp works like XREF algorithm, cmp except that it converts characters to lowercase prior to applying ($D pred). Technically, icmp(r1, r2) is equivalent to cmp!"std.uni.toLower(a) < std.uni.toLower(b)"(r1, r2).

< 0 | s1 < s2
= 0 | s1 == s2
> 0 | s1 > s2

pure nothrow immutable(char)* toStringz(const(char)[] s);
pure nothrow immutable(char)* toStringz(string s);
Returns a C-style zero-terminated string equivalent to s. s must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If s.empty is true, then a string containing only '\0' is returned.

Important Note: When passing a 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 go away during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

enum CaseSensitive;
Flag indicating whether a search is case-sensitive.

pure ptrdiff_t indexOf(Char)(in Char[] s, dchar c, CaseSensitive cs = CaseSensitive.yes);
Returns the index of the first occurence of c in s. If c is not found, then -1 is returned.

cs indicates whether the comparisons are case sensitive.

ptrdiff_t indexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, CaseSensitive cs = CaseSensitive.yes);
Returns the index of the first occurence of sub in s. If sub is not found, then -1 is returned.

cs indicates whether the comparisons are case sensitive.

ptrdiff_t lastIndexOf(Char)(const(Char)[] s, dchar c, CaseSensitive cs = CaseSensitive.yes);
Returns the index of the last occurence of c in s. If c is not found, then -1 is returned.

cs indicates whether the comparisons are case sensitive.

ptrdiff_t lastIndexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, CaseSensitive cs = CaseSensitive.yes);
Returns the index of the last occurence of sub in s. If sub is not found, then -1 is returned.

cs indicates whether the comparisons are case sensitive.

pure nothrow auto representation(Char)(Char[] s);
Returns the representation of a string, which has the same type as the string except the character type is replaced by ubyte, ushort, or uint depending on the character width.

Example:
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]);

pure @trusted S toLower(S)(S s);
Returns a string which is identical to s except that all of its characters are lowercase (in unicode, not just ASCII). If s does not have any uppercase characters, then s is returned.

void toLowerInPlace(C)(ref C[] s);
Converts s to lowercase (in unicode, not just ASCII) in place. If s does not have any uppercase characters, then s is unaltered.

pure @trusted S toUpper(S)(S s);
Returns a string which is identical to s except that all of its characters are uppercase (in unicode, not just ASCII). If s does not have any lowercase characters, then s is returned.

void toUpperInPlace(C)(ref C[] s);
Converts s to uppercase (in unicode, not just ASCII) in place. If s does not have any lowercase characters, then s is unaltered.

pure @trusted S capitalize(S)(S s);
Capitalize the first character of s and conver the rest of s to lowercase.

enum KeepTerminator;
S[] splitLines(S)(S s, KeepTerminator keepTerm = KeepTerminator.no);
Split s into an array of lines using '\r', '\n', "\r\n", std.uni.lineSep, and std.uni.paraSep as delimiters. If keepTerm is set to KeepTerminator.yes, then the delimiter is included in the strings returned.

pure @safe C[] stripLeft(C)(C[] str);
Strips leading whitespace.

Examples:
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]);

C[] stripRight(C)(C[] str);
Strips trailing whitespace.

Examples:
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");

C[] strip(C)(C[] str);
Strips both leading and trailing whitespace.

Examples:
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");

C[] chomp(C)(C[] str);
C1[] chomp(C1, C2)(C1[] str, const(C2)[] delimiter);
If str ends with delimiter, then str is returned without delimiter on its end. If it str does not end with delimiter, then it is returned unchanged.

If no delimiter is given, then one trailing '\r', '\n', "\r\n", std.uni.lineSep, or std.uni.paraSep is removed from the end of str. If str does not end with any of those characters, then it is returned unchanged.

Examples:
assert(chomp(" hello world  \n\r") == " hello world  \n");
assert(chomp(" hello world  \r\n") == " 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") == " hello world");
assert(chomp("") == "");

assert(chomp(" hello world", "orld") == " hello w");
assert(chomp(" hello world", " he") == " hello world");
assert(chomp("", "hello") == "");

C1[] chompPrefix(C1, C2)(C1[] str, C2[] delimiter);
If str starts with delimiter, then the part of str following delimiter is returned. If it str does not start with delimiter, then it is returned unchanged.

Examples:
assert(chompPrefix("hello world", "he") == "llo world");
assert(chompPrefix("hello world", "hello w") == "orld");
assert(chompPrefix("hello world", " world") == "hello world");
assert(chompPrefix("", "hello") == "");

S chop(S)(S str);
Returns str without its last character, if there is one. If str ends with "\r\n", then both are removed. If str is empty, then then it is returned unchanged.

Examples:
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("") == "");

@trusted S leftJustify(S)(S s, size_t width, dchar fillChar = ' ');
Left justify s in a field width characters wide. fillChar is the character that will be used to fill up the space in the field that s doesn't fill.

@trusted S rightJustify(S)(S s, size_t width, dchar fillChar = ' ');
Right justify s in a field width characters wide. fillChar is the character that will be used to fill up the space in the field that s doesn't fill.

@trusted S center(S)(S s, size_t width, dchar fillChar = ' ');
Center s in a field width characters wide. fillChar is the character that will be used to fill up the space in the field that s doesn't fill.

pure @trusted S detab(S)(S s, size_t tabSize = 8);
Replace each tab character in s with the number of spaces necessary to align the following character at the next tab stop where tabSize is the distance between tab stops.

pure @trusted S entab(S)(S s, size_t tabSize = 8);
Replaces spaces in s with the optimal number of tabs. All spaces and tabs at the end of a line are removed.

Parameters:
s | String to convert.
tabSize | Tab columns are tabSize spaces apart.

@safe C1[] translate(C1, C2 = immutable(char))(C1[] str, dchar[dchar] transTable, const(C2)[] toRemove = null);
@safe C1[] translate(C1, S, C2 = immutable(char))(C1[] str, S[dchar] transTable, const(C2)[] toRemove = null);
Replaces the characters in str which are keys in transTable with their corresponding values in transTable. transTable is an AA where its keys are dchar and its values are either dchar or some type of string. Also, if toRemove is given, the characters in it are removed from str prior to translation. str itself is unaltered. A copy with the changes is returned.

See Also:
tr std.array.replace

Parameters:
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.

Examples:
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");

nothrow @trusted C[] translate(C = immutable(char))(in char[] str, in char[] transTable, in char[] toRemove = null);
pure nothrow @trusted string makeTrans(in char[] from, in char[] to);
This is an ASCII-only overload of translate. It will not work with Unicode. It exists as an optimization for the cases where Unicode processing is not necessary.

Unlike the other overloads of translate, this one does not take an AA. Rather, it takes a string generated by makeTrans.

The array generated by makeTrans is 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 128 characters), but be warned that Extended ASCII characters are not valid Unicode and therefore will result in a 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 127 with another code unit or replacing any code unit with another code unit greater than 127 which will cause UTF validation issues.

See Also:
tr std.array.replace

Parameters:
str | The original string.
transTable | The string indicating which characters to replace and what to replace them with. It is generated by makeTrans.
toRemove | The characters to remove from the string.

Examples:
auto transTable1 = makeTrans("eo5", "57q");
assert(translate("hello world", transTable1) == "h5ll7 w7rld");

assert(translate("hello world", transTable1, "low") == "h5 rd");

string format(Char, Args...)(in Char[] fmt, Args args);
Format arguments into a string.

format's current implementation has been replaced with xformat's implementation. in November 2012. This is seamless for most code, but it makes it so that the only argument that can be a format string is the first one, so any code which used multiple format strings has broken. Please change your calls to format accordingly.

e.g.:
format("key = %s", key, ", value = %s", value)
needs to be rewritten as:
format("key = %s, value = %s", key, value)

char[] sformat(Char, Args...)(char[] buf, in Char[] fmt, Args args);
Format arguments into string s which must be large enough to hold the result. Throws RangeError if it is not.

Returns:
s

sformat's current implementation has been replaced with xsformat's implementation. in November 2012. This is seamless for most code, but it makes it so that the only argument that can be a format string is the first one, so any code which used multiple format strings has broken. Please change your calls to sformat accordingly.

e.g.:
sformat(buf, "key = %s", key, ", value = %s", value)
needs to be rewritten as:
sformat(buf, "key = %s, value = %s", key, value)

string xformat(Char, Args...)(in Char[] fmt, Args args);
Format arguments into a string.

format has been changed to use this implementation in November 2012. Then xformat has been scheduled for deprecation at the same time. It will be deprecateed in May 2013.

char[] xsformat(Char, Args...)(char[] buf, in Char[] fmt, Args args);
Format arguments into string buf which must be large enough to hold the result. Throws RangeError if it is not.

sformat has been changed to use this implementation in November 2012. Then xsformat has been scheduled for deprecation at the same time. It will be deprecateed in May 2013.

Returns:
filled slice of buf

bool inPattern(S)(dchar c, in S pattern);
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, S[] patterns);
See if character c is in the intersection of the patterns.

size_t countchars(S, S1)(S s, in S1 pattern);
Count characters in s that match pattern.

S removechars(S)(S s, in S pattern);
Return string that is s with all characters removed that match pattern.

S squeeze(S)(S s, in S pattern = null);
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.

S1 munch(S1, S2)(ref S1 s, S2 pattern);
Finds the position pos of the first character in s that does not match pattern (in the terminology used by inPattern). Updates s = s[pos..$]. Returns the slice from the beginning of the original (before update) string up to, and excluding, pos.

Example:
string s = "123abc";
string t = munch(s, "0123456789");
assert(t == "123" && s == "abc");
t = munch(s, "0123456789");
assert(t == "" && s == "abc");

The 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.)

S succ(S)(S s);
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.

C1[] tr(C1, C2, C3, C4 = immutable(char))(C1[] str, const(C2)[] from, const(C3)[] to, const(C4)[] modifiers = null);
Replaces the characters in str which are in from with the the corresponding characters in to and returns the resulting string.

tr is based on Posix's tr, though it doesn't do everything that the Posix utility does.

Parameters:
str | The original string.
from | The characters to replace.
to | The characters to replace with.
modifiers | String containing modifiers.

Modifiers:
Modifier | Description
'c' | Complement the list of characters in from
'd' | Removes matching characters with no corresponding replacement in to
's' | Removes adjacent duplicates in the replaced characters

If the modifier 'd' is present, then the number of characters in to may be only 0 or 1.

If the modifier 'd' is not present, and to is empty, then to is taken to be the same as from.

If the modifier 'd' is not present, and to is shorter than from, then to is extended by replicating the last charcter in to.

Both from and to may contain ranges using the '-' character (e.g. "a-d" is synonymous with "abcd.) Neither accept a leading '^' as meaning the complement of the string (use the 'c' modifier for that).

bool isNumeric(const(char)[] s, in bool bAllowSep = false);
[in] string s can be formatted in the following ways:

Integer Whole Number: (for byte, ubyte, short, ushort, int, uint, long, and ulong) ['+'|'-']digit(s)[U|L|UL]

Examples:
123, 123UL, 123L, +123U, -123L

Floating-Point Number: (for 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]

Examples:
+123., -123.01, 123.3e-10f, 123.3e-10fi, 123.3e-10L

(for 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]

Examples:
nan, -123e-1+456.9e-10Li, +123e+10+456i, 123+456

[in] bool bAllowSep False by default, but when set to true it will accept the separator characters "," and "" within the string, but these characters should be stripped from the string before using any of the conversion functions like toInt(), toFloat(), 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.

char[] soundex(const(char)[] string, char[] buffer = null);
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.

Parameters:
const(char)[] string | String to convert to Soundex representation.
char[] 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:
Wikipedia, The Soundex Indexing System

BUGS:
Only works well with English names. There are other arguably better Soundex algorithms, but this one is the standard one.

string[string] abbrev(string[] values);
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.

Example:
 import std.stdio;
 import std.string;

 void main()
 {
    static string[] list = [ "food", "foxy" ];

    auto abbrevs = std.string.abbrev(list);

    foreach (key, value; abbrevs)
    {
       writefln("%s => %s", key, value);
    }
 }
produces the output:
 fox => foxy
 food => food
 foxy => foxy
 foo => food

size_t column(S)(S str, size_t tabsize = 8);
Compute column number after string if string starts in the leftmost column, which is numbered starting from 0.

S wrap(S)(S s, size_t columns = 80, S firstindent = null, S indent = null, size_t tabsize = 8);
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.

Parameters:
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

Returns:
The resulting paragraph.

S outdent(S)(S str);
S[] outdent(S)(S[] lines);
Removes indentation from a multi-line string or an array of single-line strings.

This uniformly outdents the text as much as possible. Whitespace-only lines are always converted to blank lines.

A StringException will be thrown if inconsistent indentation prevents the input from being outdented.

Works at compile-time.

Example:
 writeln(q{
     import std.stdio;
     void main() {
         writeln("Hello");
     }
 }.outdent());

Output:
 import std.stdio;
 void main() {
     writeln("Hello");
 }

Copyright Digital Mars 2007-. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.system

Information about the target operating system, environment, and CPU.

License:
Boost License 1.0.

Authors:
Walter Bright and Jonathan M Davis

Source:
std/system.d

enum OS;
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 version(Windows), version(linux), etc.

See Also:
Predefined Versions

win32
Microsoft 32 bit Windows systems

win64
Microsoft 64 bit Windows systems

linux
All Linux Systems

osx
Mac OS X

freeBSD
FreeBSD

solaris
Solaris

otherPosix
Other Posix Systems

immutable OS os;
The OS that the program was compiled for.

enum Endian;
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 version(BigEndian) and version(LittleEndian).

See Also:
Predefined Versions

bigEndian
Big endian byte order

littleEndian
Little endian byte order

immutable Endian endian;
The endianness that the program was compiled for.

Copyright Digital Mars 2000 - 2011 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.traits

Templates with which to extract information about types and symbols at compile time.

License:
Boost License 1.0.

Authors:
Walter Bright, Tomasz Stachowiak (isExpressionTuple), Andrei Alexandrescu, Shin Fujishiro, Robert Clipsham, David Nadlinger, Kenji Hara, Shoichi Kato

Source:
std/traits.d

struct Demangle(T);

template defaultInit(T)

template packageName(alias T)
Get the full package name for the given symbol.

Example:
 import std.traits;
 static assert(packageName!packageName == "std");

template moduleName(alias T)
Get the module name (including package) for the given symbol.

Example:
 import std.traits;
 static assert(moduleName!moduleName == "std.traits");

template fullyQualifiedName(alias T)
Get the fully qualified name of a symbol.

Example:
 import std.traits;
 static assert(fullyQualifiedName!fullyQualifiedName == "std.traits.fullyQualifiedName");

template ReturnType(func...) if (func.length == 1 && isCallable!(func))
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 opCall.

Example:
 import std.traits;
 int foo();
 ReturnType!foo x;   // x is declared as int

template ParameterTypeTuple(func...) if (func.length == 1 && isCallable!(func))
Get, as a tuple, the types of the parameters to 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 opCall.

Example:
import std.traits;
int foo(int, long);
void bar(ParameterTypeTuple!foo);      // declares void bar(int, long);
void abc(ParameterTypeTuple!foo[1]);   // declares void abc(long);

template arity(alias func) if (isCallable!(func) && variadicFunctionStyle!(func) == Variadic.no)
Returns the number of arguments of function func. arity is undefined for variadic functions.

Example:
void foo(){}
static assert(arity!foo==0);
void bar(uint){}
static assert(arity!bar==1);

enum ParameterStorageClass;
template ParameterStorageClassTuple(func...) if (func.length == 1 && isCallable!(func))
Returns a tuple consisting of the storage classes of the parameters of a function func.

Example:
alias ParameterStorageClass STC; // shorten the enum name

void func(ref int ctx, out real result, real param)
{
}
alias ParameterStorageClassTuple!func pstc;
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);

none
scope_
out_
ref_
lazy_
These flags can be bitwise OR-ed together to represent complex storage class. ditto

template ParameterIdentifierTuple(func...) if (func.length == 1 && isCallable!(func))
Get, as a tuple, the identifiers of the parameters to a function symbol.

Example:
import std.traits;
int foo(int num, string name);
static assert([ParameterIdentifierTuple!foo] == ["num", "name"]);

template ParameterDefaultValueTuple(func...) if (func.length == 1 && isCallable!(func))
Get, as a tuple, the default value of the parameters to a function symbol. If a parameter doesn't have the default value, void is returned instead.

Example:
import std.traits;
int foo(int num, string name = "hello", int[] arr = [1,2,3]);
static assert(is(ParameterDefaultValueTuple!foo[0] == void));
static assert(   ParameterDefaultValueTuple!foo[1] == "hello");
static assert(   ParameterDefaultValueTuple!foo[2] == [1,2,3]);

enum FunctionAttribute;
template functionAttributes(func...) if (func.length == 1 && isCallable!(func))
Returns the attributes attached to a function func.

Example:
alias FunctionAttribute FA; // 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

none
pure_
nothrow_
ref_
property
trusted
safe
These flags can be bitwise OR-ed together to represent complex attribute. ditto

template isSafe(alias func) if (isCallable!(func))
true if func is @safe or @trusted.

Example:
@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);

template isUnsafe(alias func)
true if func is @system.

Example:
@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);

template areAllSafe(funcs...) if (funcs.length > 0)
Scheduled for deprecation in January 2013. It's badly named and provides redundant functionality. It was also badly broken prior to 2.060 (bug# 8362), so any code which uses it probably needs to be changed anyway. Please use allSatisfy(isSafe, ...) instead.

true all functions are isSafe.

Example:
@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));

template functionLinkage(func...) if (func.length == 1 && isCallable!(func))
Returns the calling convention of function as a string.

Example:
string a = functionLinkage!(writeln!(string, int));
assert(a == "D"); // extern(D)

auto fp = &printf;
string b = functionLinkage!fp;
assert(b == "C"); // extern(C)

enum Variadic;
template variadicFunctionStyle(func...) if (func.length == 1 && isCallable!(func))
Determines what kind of variadic parameters function has.

Example:
void func() {}
static assert(variadicFunctionStyle!func == Variadic.no);

extern(C) int printf(in char*, ...);
static assert(variadicFunctionStyle!printf == Variadic.c);

no
Function is not variadic.

c
Function is a C-style variadic function.

d
Function is a D-style variadic function, which uses _argptr and _arguments.

typesafe
Function is a typesafe variadic function.

template FunctionTypeOf(func...) if (func.length == 1 && isCallable!(func))
Get the function type from a callable object func.

Using builtin typeof on a property function yields the types of the property value, not of the property function itself. Still, FunctionTypeOf is able to obtain function types of properties.
class C
{
    int value() @property;
}
static assert(is( typeof(C.value) == int ));
static assert(is( FunctionTypeOf!(C.value) == function ));

Note:
Do not confuse function types with function pointer types; function types are usually used for compile-time reflection purposes.

template SetFunctionAttributes(T, string linkage, uint attrs) if (isFunctionPointer!(T) || isDelegate!(T))
template SetFunctionAttributes(T, string linkage, uint attrs) if (is(T == function))
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 from/to types in generic code, where the actual type name cannot be spelt out.

Parameters:
T | The base type.
linkage | The desired linkage of the result type.
attrs | The desired FunctionAttributes of the result type.

Examples:
 template ExternC(T)
     if (isFunctionPointer!T || isDelegate!T || is(T == function))
 {
     alias SetFunctionAttributes!(T, "C", functionAttributes!T) ExternC;
 }

 auto assumePure(T)(T t)
     if (isFunctionPointer!T || isDelegate!T)
 {
     enum attrs = functionAttributes!T | FunctionAttribute.pure_;
     return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
 }

template FieldTypeTuple(S)
Get the types of the fields of a struct or class. This consists of the fields that take up memory space, excluding the hidden fields like the virtual function table pointer.

template RepresentationTypeTuple(T)
Get the primitive types of the fields of a struct or class, in topological order.

Example:
struct S1 { int a; float b; }
struct S2 { char[] a; union { S1 b; S1 * c; } }
alias RepresentationTypeTuple!S2 R;
assert(R.length == 4
    && is(R[0] == char[]) && is(R[1] == int)
    && is(R[2] == float) && is(R[3] == S1*));

template hasAliasing(T...)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U* and U is not immutable;
  2. an array U[] and U is not immutable;
  3. a reference to a class or interface type C and C is not immutable.
  4. an associative array that is not immutable.
  5. a delegate.

template hasIndirections(T)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U*;
  2. an array U[];
  3. a reference to a class type C.
  4. an associative array.
  5. a delegate.

template hasUnsharedAliasing(T...)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U* and U is not immutable or shared;
  2. an array U[] and U is not immutable or shared;
  3. a reference to a class type C and C is not immutable or shared.
  4. an associative array that is not immutable or shared.
  5. a delegate that is not shared.

template hasElaborateCopyConstructor(S)
True if S or any type embedded directly in the representation of S defines an elaborate copy constructor. Elaborate copy constructors are introduced by defining this(this) for a struct. (Non-struct types never have elaborate copy constructors.)

template hasElaborateAssign(S)
True if S or any type directly embedded in the representation of S defines an elaborate assignment. Elaborate assignments are introduced by defining opAssign(typeof(this)) or opAssign(ref typeof(this)) for a struct. (Non-struct types never have elaborate assignments.)

template hasElaborateDestructor(S)
True if S or any type directly embedded in the representation of S defines an elaborate destructor. Elaborate destructors are introduced by defining ~this() for a struct. (Non-struct types never have elaborate destructors, even though classes may define ~this().)

template hasMember(T, string name)
Yields true if and only if T is an aggregate that defines a symbol called name.

template EnumMembers(E) if (is(E == enum))
Retrieves the members of an enumerated type enum E.

Parameters:
E An enumerated type. E may have duplicated values.

Returns:
Static tuple composed of the members of the enumerated type E. The members are arranged in the same order as declared in E.

Note:
Returned values are strictly typed with 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.

Examples:
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 rank(v) in the following example uses this template for finding a member e in an enumerated type 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 BaseTypeTuple(A)
Get a TypeTuple of the base class and base interfaces of this class or interface. BaseTypeTuple!Object returns the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }

 void main()
 {
     alias BaseTypeTuple!B TL;
     writeln(typeid(TL));        // prints: (A,I)
 }

template BaseClassesTuple(T)
Get a TypeTuple of all base classes of this class, in decreasing order. Interfaces are not included. BaseClassesTuple!Object yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }
 class C : B { }

 void main()
 {
     alias BaseClassesTuple!C TL;
     writeln(typeid(TL));        // prints: (B,A,Object)
 }

template InterfacesTuple(T)
Get a TypeTuple of all interfaces directly or indirectly inherited by this class or interface. Interfaces do not repeat if multiply implemented. InterfacesTuple!Object yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I1 { }
 interface I2 { }
 class A : I1, I2 { }
 class B : A, I1 { }
 class C : B { }

 void main()
 {
     alias InterfacesTuple!C TL;
     writeln(typeid(TL));        // prints: (I1, I2)
 }

template TransitiveBaseTypeTuple(T)
Get a TypeTuple of all base classes of T, in decreasing order, followed by T's interfaces. TransitiveBaseTypeTuple!Object yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }
 class C : B { }

 void main()
 {
     alias TransitiveBaseTypeTuple!C TL;
     writeln(typeid(TL));        // prints: (B,A,Object,I)
 }

template MemberFunctionsTuple(C, string name) if (is(C == class) || is(C == interface))
Returns a tuple of non-static functions with the name name declared in the class or interface C. Covariant duplicates are shrunk into the most derived one.

Example:
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 MemberFunctionsTuple!(C, "foo") foos;
static assert(foos.length == 2);
static assert(__traits(isSame, foos[0], C.foo));
static assert(__traits(isSame, foos[1], B.foo));

template classInstanceAlignment(T) if (is(T == class))
Returns class instance alignment.

Example:
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);

template CommonType(T...)
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 void if passed an empty list, or if the types have no common type.

Example:
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(int, char[], short) Y;
assert(is(Y == void));

template ImplicitConversionTargets(T)
Returns a tuple with all possible target types of an implicit conversion of a value of type T.

Important note:

The possible targets are computed more conservatively than the D 2.005 compiler does, eliminating all dangerous conversions. For example, ImplicitConversionTargets!double does not include float.

template isImplicitlyConvertible(From, To)
Is From implicitly convertible to To?

template isAssignable(Lhs, Rhs = Lhs)
Returns true iff a value of type Rhs can be assigned to a variable of type Lhs.

If you omit Rhs, isAssignable will check identity assignable of Lhs.

Examples:
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 assinable to immutable int
static assert(!isAssignable!(immutable int));

template isCovariantWith(F, G) if (is(F == function) && is(G == function))
Determines whether the function type F is covariant with G, i.e., functions of the type F can override ones of the type G.

Example:
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)));

template isBoolean(T)
Detect whether T is a built-in boolean type.

template isIntegral(T)
Detect whether T is a built-in integral type. Types bool, char, wchar, and dchar are not considered integral.

template isFloatingPoint(T)
Detect whether T is a built-in floating point type.

template isNumeric(T)
Detect whether T is a built-in numeric type (integral or floating point).

template isScalarType(T)
Detect whether T is a scalar type.

template isBasicType(T)
Detect whether T is a basic type.

template isUnsigned(T)
Detect whether T is a built-in unsigned numeric type.

template isSigned(T)
Detect whether T is a built-in signed numeric type.

template isSomeChar(T)
Detect whether T is one of the built-in character types.

template isSomeString(T)
Detect whether T is one of the built-in string types.

template isStaticArray(T)
Detect whether type T is a static array.

template isDynamicArray(T)
Detect whether type T is a dynamic array.

template isArray(T)
Detect whether type T is an array.

template isAssociativeArray(T)
Detect whether T is an associative array type

template isPointer(T)
Detect whether type T is a pointer.

template PointerTarget(T : T*)
Returns the target type of a pointer.

alias PointerTarget(T : T*) pointerTarget;
Scheduled for deprecation. Please use PointerTarget instead.

template isAggregateType(T)
Detect whether type T is an aggregate type.

template isIterable(T)
Returns true if T can be iterated over using a foreach loop with a single loop variable of automatically inferred type, regardless of how the foreach loop is implemented. This includes ranges, structs/classes that define opApply with a single loop variable, and builtin dynamic, static and associative arrays.

template isMutable(T)
Returns true if T is not const or immutable. Note that isMutable is true for string, or immutable(char)[], because the 'head' is mutable.

template isInstanceOf(alias S, T)
Returns true if T is an instance of the template S.

template isExpressionTuple(T...)
Tells whether the tuple T is an expression tuple.

template isTypeTuple(T...)
Detect whether tuple T is a type tuple.

template isFunctionPointer(T...) if (T.length == 1)
Detect whether symbol or type T is a function pointer.

template isDelegate(T...) if (T.length == 1)
Detect whether T is a delegate.

template isSomeFunction(T...) if (T.length == 1)
Detect whether symbol or type T is a function, a function pointer or a delegate.

template isCallable(T...) if (T.length == 1)
Detect whether T is a callable object, which can be called with the function call operator (...).

template isAbstractFunction(method...) if (method.length == 1)
Exactly the same as the builtin traits: __traits(isAbstractFunction, method).

template Unqual(T)
Removes all qualifiers, if any, from type T.

Example:
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));

template ForeachType(T)
Returns the inferred type of the loop variable when a variable of type T is iterated over using a foreach loop with a single loop variable and automatically inferred return type. Note that this may not be the same as std.range.ElementType!Range in the case of narrow strings, or if T has both opApply and a range interface.

template OriginalType(T)
Strips off all typedefs (including enum ones) from type T.

Example:
enum E : int { a }
typedef E F;
typedef const F G;
static assert(is(OriginalType!G == const int));

template KeyType(V : V[K], K)
Get the Key type of an Associative Array.

Example:
 import std.traits;
 alias int[string] Hash;
 static assert(is(KeyType!Hash == string));
 KeyType!Hash str = "string";   // str is declared as string

template ValueType(V : V[K], K)
Get the Value type of an Associative Array.

Example:
 import std.traits;
 alias int[string] Hash;
 static assert(is(ValueType!Hash == int));
 ValueType!Hash num = 1;   // num is declared as int

template Unsigned(T)
Returns the corresponding unsigned type for T. T must be a numeric integral type, otherwise a compile-time error occurs.

template Largest(T...) if (T.length >= 1)
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 Signed(T)
Returns the corresponding signed type for T. T must be a numeric integral type, otherwise a compile-time error occurs.

auto unsigned(T)(T x);
Returns the corresponding unsigned value for x, e.g. if x has type int, returns cast(uint) x. The advantage compared to the cast is that you do not need to rewrite the cast if x later changes type to e.g. long.

template mostNegative(T) if (isNumeric!(T) || isSomeChar!(T))
Returns the most negative value of the numeric type T.

template mangledName(sth...) if (sth.length == 1)
Returns the mangled name of symbol or type sth.

mangledName is the same as builtin .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 Select(bool condition, T, F)
Aliases itself to T if the boolean condition is true and to F otherwise.

Example:
alias Select!(size_t.sizeof == 4, int, long) Int;

A select(bool cond : true, A, B)(A a, lazy B b);
B select(bool cond : false, A, B)(lazy A a, B b);
If cond is true, returns a without evaluating b. Otherwise, returns b without evaluating a.

Copyright Digital Mars 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.typecons

This module implements a variety of type constructors, i.e., templates that allow construction of new, useful general-purpose types.

Source:
std/typecons.d

Synopsis:
// value tuples
alias Tuple!(float, "x", float, "y", float, "z") Coord;
Coord c;
c[1] = 1;       // access by index
c.z = 1;        // access by given name
alias Tuple!(string, string) DicEntry; // 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;
}

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, Bartosz Milewski, Don Clugston, Shin Fujishiro, Kenji Hara

struct Unique(T);
Encapsulates unique ownership of a resource. Resource of type T is deleted at the end of the scope, unless it is transferred. The transfer can be explicit, by calling release, or implicit, when returning Unique from a function. The resource can be a polymorphic class object, in which case Unique behaves polymorphically too.

Example:

this(RefT p);
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(ref RefT 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.

Unique release();
Returns a unique rvalue. Nullifies the current contents

RefT opDot();
Forwards member access to contents

struct Tuple(Specs...);
Tuple of values, for example Tuple!(int, string) is a record that stores an int and a string. Tuple can be used to bundle values together, notably when returning multiple values from a function. If obj is a tuple, the individual members are accessible with the syntax obj[0] for the first field, 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 tuples with various compile-time loop constructs (e.g. type tuple iteration), all of which use zero-based indexing.

Example:
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.

Example:
alias Tuple!(int, "index", string, "value") Entry;
Entry e;
e.index = 4;
e.value = "Hello";
assert(e[1] == "Hello");
assert(e[0] == 4);

Tuples with named fields are distinct types from tuples with unnamed fields, i.e. each naming imparts a separate type for the tuple. Two tuple differing in naming only are still distinct, even though they might have the same structure.

Example:
Tuple!(int, "x", int, "y") point1;
Tuple!(int, int) point2;
assert(!is(typeof(point1) == typeof(point2))); // passes

alias staticMap!(extractType, fieldSpecs) Types;
The type of the tuple's components.

this(U...)(U values);
Constructor taking one value for each field. Each argument must be implicitly assignable to the respective element of the target.

this(U)(U another);
Constructor taking a compatible tuple. Each element of the source must be implicitly assignable to the respective element of the target.

bool opEquals(R)(R rhs);
const bool opEquals(R)(R rhs);
Comparison for equality.

int opCmp(R)(R rhs);
const int opCmp(R)(R rhs);
Comparison for ordering.

void opAssign(R)(R rhs);
Assignment from another tuple. Each element of the source must be implicitly assignable to the respective element of the target.

Tuple!(sliceSpecs!(from, to)) slice(uint from, uint to)();
Takes a slice of the tuple.

Example:
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);

string toString();
Converts to string.

Tuple!(T) tuple(T...)(T args);
Returns a Tuple object instantiated and initialized according to the arguments.

Example:
auto value = tuple(5, 6.7, "hello");
assert(value[0] == 5);
assert(value[1] == 6.7);
assert(value[2] == "hello");

template isTuple(T)
Returns true if and only if T is an instance of the Tuple struct template.

template Rebindable(T) if (is(T == class) || is(T == interface) || isArray!(T))
Rebindable!(T) is a simple, efficient wrapper that behaves just like an object of type T, except that you can reassign it to refer to another object. For completeness, Rebindable!(T) aliases itself away to T if T is a non-const object type. However, Rebindable!(T) does not compile if T is a non-class type.

Regular const object references cannot be reassigned:

class Widget { int x; int y() const { return a; } }
const a = new Widget;
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // error! can't modify const a

However, Rebindable!(Widget) does allow reassignment, while otherwise behaving exactly like a const Widget:

auto a = Rebindable!(const Widget)(new Widget);
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // fine

You may want to use Rebindable when you want to have mutable storage referring to const objects, for example an array of references that must be sorted in place. Rebindable does not break the soundness of D's type system and does not incur any of the risks usually associated with cast.

Rebindable!(T) rebindable(T)(T obj);
Convenience function for creating a Rebindable using automatic type inference.

Rebindable!(T) rebindable(T)(Rebindable!(T) obj);
This function simply returns the Rebindable object passed in. It's useful in generic programming cases when a given object may be either a regular class or a Rebindable.

string alignForSize(E...)(string[] names...);
Order the provided members to minimize size while preserving alignment. Returns a declaration to be mixed in.

Example:
struct Banner {
  mixin(alignForSize!(byte[6], double)(["name", "height"]));
}

Alignment is not always optimal for 80-bit reals, nor for structs declared as align(1).

struct Nullable(T);
Defines a value paired with a distinctive "null" state that denotes the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it non-null. Calling nullify can nullify it again.

Example:
Nullable!int a;
assert(a.isNull);
a = 5;
assert(!a.isNull);
assert(a == 5);

Practically Nullable!T stores a T and a bool.

this()(T value);
Constructor initializing this with value.

const pure nothrow @safe bool isNull();
Returns true if and only if this is in the null state.

void nullify()();
Forces this to the null state.

void opAssign()(T value);
Assigns value to the internally-held state. If the assignment succeeds, this becomes non-null.

inout pure @safe inout(T) get();
Gets the value. Throws an exception if this is in the null state. This function is also called for the implicit conversion to T.

struct Nullable(T, T nullValue);
Just like Nullable!T, except that the null state is defined as a particular value. For example, Nullable!(uint, uint.max) is an uint that sets aside the value uint.max to denote a null state. Nullable!(T, nullValue) is more storage-efficient than Nullable!T because it does not need to store an extra bool.

this()(T value);
Constructor initializing this with value.

const bool isNull()();
Returns true if and only if this is in the null state.

void nullify()();
Forces this to the null state.

void opAssign()(T value);
Assigns value to the internally-held state. No null checks are made.

inout inout(T) get()();
Gets the value. Throws an exception if this is in the null state. This function is also called for the implicit conversion to T.

struct NullableRef(T);
Just like Nullable!T, except that the object refers to a value sitting elsewhere in memory. This makes assignments overwrite the initially assigned value. Internally NullableRef!T only stores a pointer to T (i.e., Nullable!T.sizeof == (T*).sizeof).

pure nothrow @safe this(T* value);
Constructor binding this with value.

pure nothrow @safe void bind(T* value);
Binds the internal state to value.

const pure nothrow @safe bool isNull();
Returns true if and only if this is in the null state.

pure nothrow @safe void nullify();
Forces this to the null state.

void opAssign()(T value);
Assigns value to the internally-held state.

inout inout(T) get()();
Gets the value. Throws an exception if this is in the null state. This function is also called for the implicit conversion to T.

template BlackHole(Base)
BlackHole!Base is a subclass of Base which automatically implements all abstract member functions in 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 Class::BlackHole Perl module by Sean M. Burke.

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

void main()
{
    auto c = new BlackHole!C(42);
    writeln(c.value);     // prints "42"

    // Abstract functions are implemented as do-nothing:
    writeln(c.realValue); // prints "NaN"
    c.doSomething();      // does nothing
}

See Also:
AutoImplement, generateEmptyFunction

template WhiteHole(Base)
WhiteHole!Base is a subclass of Base which automatically implements all abstract member functions as throw-always functions. Each auto-implemented function fails with throwing an Error and does never return. Useful for trapping use of not-yet-implemented functions.

The name came from Class::WhiteHole Perl module by Michael G Schwern.

Example:
class C
{
    abstract void notYetImplemented();
}

void main()
{
    auto c = new WhiteHole!C;
    c.notYetImplemented(); // throws an Error
}

BUGS:
Nothrow functions cause program to abort in release mode because the trap is implemented with assert(0) for nothrow functions.

See Also:
AutoImplement, generateAssertTrap

class AutoImplement(Base, alias how, alias what = isAbstractFunction): Base;
AutoImplement automatically implements (by default) all abstract member functions in the class or interface Base in specified way.

Parameters:
how template which specifies how functions will be implemented/overridden.

Two arguments are passed to how: the type Base and an alias to an implemented function. Then how must return an implemented function body as a string.

The generated function body can use these keywords:
  • a0, a1, …: arguments passed to the function;
  • args: a tuple of the arguments;
  • self: an alias to the function itself;
  • 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
{
    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(typeof(return) == 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 what: an alias to a non-final member function in Base. Then what must return a boolean value. Return true to indicate that the passed function should be implemented/overridden.

// Sees if fun returns something.
template hasValue(alias fun)
{
    enum bool hasValue = !is(ReturnType!(fun) == void);
}

Note:
Generated code is inserted in the scope of std.typecons module. Thus, any useful functions outside std.typecons cannot be used in the generated code. To workaround this problem, you may import necessary things in a local struct, as done in the generateLogger() template in the above example.

BUGS:
  • Variadic arguments to constructors are not forwarded to super.
  • 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]
  • The parent keyword is actually a delegate to the super class' corresponding member function. [Bugzilla 2540]
  • Using alias template parameter in how and/or what may cause strange compile error. Use template tuple parameter instead to workaround this problem. [Bugzilla 4217]

template generateEmptyFunction(C, func...)
template generateAssertTrap(C, func...)
Predefined how-policies for AutoImplement. These templates are used by BlackHole and WhiteHole, respectively.

enum RefCountedAutoInitialize;
Options regarding auto-initialization of a RefCounted object (see the definition of RefCounted below).

no
Do not auto-initialize the object

yes
Auto-initialize the object

struct RefCounted(T, RefCountedAutoInitialize autoInit = RefCountedAutoInitialize.yes) if (!is(T == class));
Defines a reference-counted object containing a T value as payload. RefCounted keeps track of all references of an object, and when the reference count goes down to zero, frees the underlying store. RefCounted uses malloc and free for operation.

RefCounted is unsafe and should be used with care. No references to the payload should be escaped outside the RefCounted object.

The autoInit option makes the object ensure the store is automatically initialized. Leaving autoInit == RefCountedAutoInitialize.yes (the default option) is convenient but has the cost of a test whenever the payload is accessed. If autoInit == RefCountedAutoInitialize.no, user code must call either refCountedIsInitialized or refCountedEnsureInitialized before attempting to access the payload. Not doing so results in null pointer dereference.

Example:
// A pair of an int and a 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

struct RefCountedStore;
RefCounted storage implementation.

const bool isInitialized();
Returns true if and only if the underlying store has been allocated and initialized.

const size_t refCount();
Returns underlying reference count if it is allocated and initialized (a positive integer), and 0 otherwise.

void ensureInitialized();
Makes sure the payload was properly initialized. Such a call is typically inserted before using the payload.

inout inout(RefCountedStore) refCountedStore();
Returns storage implementation struct.

this(A...)(auto ref A args);
Constructor that initializes the payload.

Postcondition:
refCountedIsInitialized

void opAssign(typeof(this) rhs);
void opAssign(T rhs);
Assignment operators

T refCountedPayload();
inout inout(T) refCountedPayload();
Returns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls refCountedEnsureInitialized. Otherwise, just issues assert(refCountedIsInitialized). Used with alias refCountedPayload this;, so callers can just use the RefCounted object as a T.

The first overload exists only if autoInit == RefCountedAutoInitialize.yes. So if autoInit == RefCountedAutoInitialize.no or called for a constant or immutable object, then refCountedPayload will also be qualified as safe and nothrow (but will still assert if not initialized).

template Proxy(alias a)
Make proxy for a.

Example:
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);

template Typedef(T)
struct Typedef(T, T init, string cookie = null);
Library typedef.

@system auto scoped(T, Args...)(auto ref Args args);
Allocates a class object right inside the current scope, therefore avoiding the overhead of 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 is no pointers to it.

Example:
unittest
{
    class A { int x; }
    auto a1 = scoped!A();
    auto a2 = scoped!A();
    a1.x = 42;
    a2.x = 53;
    assert(a1.x == 42);

    auto a3 = a2; // illegal, fails to compile
    assert([a2][0].x == 42); // illegal, unexpected behaviour
}

template Flag(string name)
Defines a simple, self-documenting yes/no flag. This makes it easy for APIs to define functions accepting flags without resorting to bool, which is opaque in calls, and without needing to define an enumerated type separately. Using Flag!"Name" instead of 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:
// Before
string getLine(bool keepTerminator)
{
    ...
    if (keepTerminator) ...
    ...
}
...
// Code calling getLine (usually far away from its definition) can't
// be understood without looking at the documentation, even by users
// familiar with the API. Assuming the reverse meaning
// (i.e. "ignoreTerminator") and inserting the wrong code compiles and
// runs with erroneous results.
auto line = getLine(false);

// After
string getLine(Flag!"KeepTerminator" keepTerminator)
{
    ...
    if (keepTerminator) ...
    ...
}
...
// Code calling getLine can be easily read and understood even by
// people not fluent with the API.
auto line = getLine(Flag!"KeepTerminator".yes);

Passing categorical data by means of unstructured bool parameters is classified under "simple-data coupling" by Steve McConnell in the 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. Flag offers a simple structuring method for passing yes/no flags to APIs.

As a perk, the flag's name may be any string and as such can include characters not normally allowed in identifiers, such as spaces and dashes.

enum Flag;

no
When creating a value of type Flag!"Name", use Flag!"Name".no for the negative option. When using a value of type Flag!"Name", compare it against Flag!"Name".no or just false or 0.

yes
When creating a value of type Flag!"Name", use Flag!"Name".yes for the affirmative option. When using a value of type Flag!"Name", compare it against Flag!"Name".yes.

struct Yes;
No">struct No">No;
Convenience names that allow using e.g. Yes.encryption instead of Flag!"encryption".yes and No.encryption instead of Flag!"encryption".no.

Copyright the respective authors, 2008- | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.typetuple

Templates with which to manipulate type tuples (also known as type lists).

Some operations on type tuples are built in to the language, such as TL[n] which gets the nth type from the type tuple. TL[lwr .. 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 template predicates.

References:
Based on ideas in Table 3.1 from Modern C++ Design, Andrei Alexandrescu (Addison-Wesley Professional, 2001)

License:
Boost License 1.0.

Authors:
Walter Bright, David Nadlinger

Source:
std/typetuple.d

template TypeTuple(TList...)
Creates a typetuple out of a sequence of zero or more types.

Example:
 import std.typetuple;
 alias TypeTuple!(int, double) TL;

 int foo(TL td)  // same as int foo(int, double);
 {
    return td[0] + cast(int)td[1];
 }

Example:
 TypeTuple!(TL, char)
 // is equivalent to:
 TypeTuple!(int, double, char)

template staticIndexOf(T, TList...)
template staticIndexOf(alias T, TList...)
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.

Example:
 import std.typetuple;
 import std.stdio;

 void foo()
 {
    writefln("The index of long is %s",
          staticIndexOf!(long, TypeTuple!(int, long, double)));
    // prints: The index of long is 1
 }

alias staticIndexOf(T, TList...) IndexOf;
Kept for backwards compatibility

template Erase(T, TList...)
template Erase(alias T, TList...)
Returns a typetuple created from TList with the first occurrence, if any, of T removed.

Example:
 Erase!(long, int, long, double, char)
 // is the same as:
 TypeTuple!(int, double, char)

template EraseAll(T, TList...)
template EraseAll(alias T, TList...)
Returns a typetuple created from TList with the all occurrences, if any, of T removed.

Example:
 alias TypeTuple!(int, long, long, int) TL;

 EraseAll!(long, TL)
 // is the same as:
 TypeTuple!(int, int)

template NoDuplicates(TList...)
Returns a typetuple created from TList with the all duplicate types removed.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 NoDuplicates!(TL)
 // is the same as:
 TypeTuple!(int, long, float)

template Replace(T, U, TList...)
template Replace(alias T, U, TList...)
template Replace(T, alias U, TList...)
template Replace(alias T, alias U, TList...)
Returns a typetuple created from TList with the first occurrence of type T, if found, replaced with type U.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 Replace!(long, char, TL)
 // is the same as:
 TypeTuple!(int, char, long, int, float)

template ReplaceAll(T, U, TList...)
template ReplaceAll(alias T, U, TList...)
template ReplaceAll(T, alias U, TList...)
template ReplaceAll(alias T, alias U, TList...)
Returns a typetuple created from TList with all occurrences of type T, if found, replaced with type U.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 ReplaceAll!(long, char, TL)
 // is the same as:
 TypeTuple!(int, char, char, int, float)

template Reverse(TList...)
Returns a typetuple created from TList with the order reversed.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 Reverse!(TL)
 // is the same as:
 TypeTuple!(float, int, long, long, int)

template MostDerived(T, TList...)
Returns the type from TList that is the most derived from type T. If none are found, T is returned.

Example:
 class A { }
 class B : A { }
 class C : B { }
 alias TypeTuple!(A, C, B) TL;

 MostDerived!(Object, TL) x;  // x is declared as type C

template DerivedToFront(TList...)
Returns the typetuple TList with the types sorted so that the most derived types come first.

Example:
 class A { }
 class B : A { }
 class C : B { }
 alias TypeTuple!(A, C, B) TL;

 DerivedToFront!(TL)
 // is the same as:
 TypeTuple!(C, B, A)

template staticMap(alias F, T...)
Evaluates to TypeTuple!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1])).

Example:
alias staticMap!(Unqual, int, const int, immutable int) T;
static assert(is(T == TypeTuple!(int, int, int)));

template allSatisfy(alias F, T...)
Tests whether all given items satisfy a template predicate, i.e. evaluates to F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).

Evaluation is not short-circuited if a false result is encountered; the template predicate must be instantiable with all the given items.

Example:
static assert(!allSatisfy!(isIntegral, int, double));
static assert(allSatisfy!(isIntegral, int, long));

template anySatisfy(alias F, T...)
Tests whether all given items satisfy a template predicate, i.e. evaluates to F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1]).

Evaluation is not short-circuited if a true result is encountered; the template predicate must be instantiable with all the given items.

Example:
static assert(!anySatisfy!(isIntegral, string, double));
static assert(anySatisfy!(isIntegral, int, double));

template Filter(alias pred, TList...)
Filters a TypeTuple using a template predicate. Returns a TypeTuple of the elements which satisfy the predicate.

Examples:
static assert(is(Filter!(isNarrowString, string, wstring,
                         dchar[], char[], dstring, int) ==
                 TypeTuple!(string, wstring, char[])));
static assert(is(Filter!(isUnsigned, int, byte, ubyte,
                         dstring, dchar, uint, ulong) ==
                 TypeTuple!(ubyte, uint, ulong)));

template templateNot(alias pred)
Negates the passed template predicate.

Examples:
 alias templateNot!isPointer isNoPointer;
 static assert(!isNoPointer!(int*));
 static assert(allSatisfy!(isNoPointer, string, char, float));

template templateAnd(Preds...)
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.

Examples:
 alias templateAnd!(isNumeric, templateNot!isUnsigned) storesNegativeNumbers;
 static assert(storesNegativeNumbers!int);
 static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint);

 // An empty list of predicates always yields true.
 alias templateAnd!() alwaysTrue;
 static assert(alwaysTrue!int);

template templateOr(Preds...)
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.

Examples:
 alias templateOr!(isPointer, isUnsigned) isPtrOrUnsigned;
 static assert(isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*));
 static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!string);

 // An empty list of predicates never yields true.
 alias templateOr!() alwaysFalse;
 static assert(!alwaysFalse!int);

Copyright Digital Mars 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.uni

Functions which operate on Unicode characters.

For functions which operate on ASCII characters and ignore Unicode characters, see std.ascii.

References:
ASCII Table, Wikipedia, The Unicode Consortium

Trademarks:
Unicode(tm) is a trademark of Unicode, Inc.

License:
Boost License 1.0.

Authors:
Walter Bright, Jonathan M Davis, and Kenji Hara

Source:
std/uni.d

dchar lineSep;
UTF line separator

dchar paraSep;
UTF paragraph separator

pure nothrow @safe bool isWhite(dchar c);
Whether or not 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))

pure nothrow @safe bool isLower(dchar c);
Return whether c is a Unicode lowercase character.

pure nothrow @safe bool isUpper(dchar c);
Return whether c is a Unicode uppercase character.

pure nothrow @safe dchar toLower(dchar c);
If c is a Unicode uppercase character, then its lowercase equivalent is returned. Otherwise c is returned.

pure nothrow @safe dchar toUpper(dchar c);
If c is a Unicode lowercase character, then its uppercase equivalent is returned. Otherwise c is returned.

pure nothrow @safe bool isAlpha(dchar c);
Returns whether c is a Unicode alpha character (general Unicode category: Lu, Ll, Lt, Lm, and Lo).

Standards:
Unicode 5.0.0.

pure nothrow @safe bool isMark(dchar c);
Returns whether c is a Unicode mark (general Unicode category: Mn, Me, Mc).

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isNumber(dchar c);
Returns whether c is a Unicode numerical character (general Unicode category: Nd, Nl, No).

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isPunctuation(dchar c);
Returns whether c is a Unicode punctuation character (general Unicode category: Pd, Ps, Pe, Pc, Po, Pi, Pf).

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isSymbol(dchar c);
Returns whether c is a Unicode symbol character (general Unicode category: Sm, Sc, Sk, So)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isSpace(dchar c);
Returns whether c is a Unicode whitespace character (general Unicode category: Zs)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isGraphical(dchar c);
Returns whether c is a Unicode graphical character (general Unicode category: L, M, N, P, S, Zs).

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isControl(dchar c);
Returns whether c is a Unicode control character (general Unicode category: Cc)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isFormat(dchar c);
Returns whether c is a Unicode formatting character (general Unicode category: Cf)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isPrivateUse(dchar c);
Returns whether c is a Unicode Private Use character (general Unicode category: Co)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isSurrogate(dchar c);
Returns whether c is a Unicode surrogate character (general Unicode category: Cs)

Standards:
Unicode 6.0.0.

pure nothrow @safe bool isSurrogateHi(dchar c);
Returns whether c is a Unicode high surrogate (lead surrogate).

Standards:
Unicode 2.0.

pure nothrow @safe bool isSurrogateLo(dchar c);
Returns whether c is a Unicode low surrogate (trail surrogate).

Standards:
Unicode 2.0.

pure nothrow @safe bool isNonCharacter(dchar c);
Returns whether c is a Unicode non-character (general Unicode category: Cn)

Standards:
Unicode 6.0.0.

Copyright 2000 - | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.uri

Encode and decode Uniform Resource Identifiers (URIs). URIs are used in internet transfer protocols. Valid URI characters consist of letters, digits, and the characters ;/?:@&=+$,-.!~*'() Reserved URI characters are ;/?:@&=+$, Escape sequences consist of % followed by two hex digits.

See Also:
RFC 3986
Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/uri.d

string decode(string encodedURI);
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 decodeComponent(string encodedURIComponent);
Decodes the URI string encodedURI into a UTF-8 string and returns it. All escape sequences are decoded.

string encode(string uri);
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 encodeComponent(string uriComponent);
Encodes the UTF-8 string uriComponent into a URI and returns that URI. Any character not a letter, digit, or one of -.!~*'() is escaped.

size_t uriLength(string s);
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

size_t emailLength(string s);
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

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.utf

Encode and decode UTF-8, UTF-16 and UTF-32 strings.

UTF character support is restricted to '\u0000' <= character <= '\U0010FFFF'.

See Also:
Wikipedia
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335

License:
Boost License 1.0.

Authors:
Walter Bright and Jonathan M Davis

Source:
std/utf.d

class UTFException: object.Exception;
Exception thrown on errors in std.utf functions.

deprecated alias UTFException UtfException;
Deprecated. It will be removed in January 2013. Please use UTFException instead.

pure nothrow @safe bool isValidDchar(dchar c);
Returns whether c is a valid UTF-32 character.

'\uFFFE' and '\uFFFF' are considered valid by isValidDchar, as they are permitted for internal use by an application, but they are not allowed for interchange by the Unicode standard.

uint stride(S)(auto ref S str, size_t index);
uint stride(S)(auto ref S str);
stride returns the length of the UTF-8 sequence starting at index in str.

stride works with both UTF-8 strings and ranges of char. If no index is passed, then an input range will work, but if an index is passed, then a random-access range is required.

index defaults to 0 if none is passed.

Returns:
The number of bytes in the UTF-8 sequence.

Throws:
May throw a UTFException if str[index] is not the start of a valid UTF-8 sequence.

Notes:
stride will only analize the first str[index] element. It will not fully verify the validity of UTF-8 sequence, nor even verify the presence of the sequence: it will not actually guarantee that index + stride(str, index) <= str.length.

uint strideBack(S)(auto ref S str, size_t index);
uint strideBack(S)(auto ref S str);
strideBack returns the length of the UTF-8 sequence ending one code unit before index in str.

strideBack works with both UTF-8 strings and bidirectional ranges of char. If no index is passed, then a bidirectional range will work, but if an index is passed, then a random-access range is required.

index defaults to str.length if none is passed.

Returns:
The number of bytes in the UTF-8 sequence.

Throws:
May throw a UTFException if str[index] is not one past the end of a valid UTF-8 sequence.

Notes:
strideBack will not fully verify the validity of the UTF-8 sequence. It will, however, guarantee that index - stride(str, index) is a valid index.

uint stride(S)(auto ref S str, size_t index);
pure @safe uint stride(S)(auto ref S str);
stride returns the length of the UTF-16 sequence starting at index in str.

stride works with both UTF-16 strings and ranges of wchar. If no index is passed, then an input range will work, but if an index is passed, then a random-access range is required.

index defaults to 0 if none is passed.

Returns:
The number of bytes in the UTF-16 sequence.

Throws:
May throw a UTFException if str[index] is not the start of a valid UTF-16 sequence.

Notes:
stride will only analize the first str[index] element. It will not fully verify the validity of UTF-16 sequence, nor even verify the presence of the sequence: it will not actually guarantee that index + stride(str, index) <= str.length.

uint strideBack(S)(auto ref S str, size_t index);
uint strideBack(S)(auto ref S str);
strideBack returns the length of the UTF-16 sequence ending one code unit before index in str.

strideBack works with both UTF-16 strings and ranges of wchar. If no index is passed, then a bidirectional range will work, but if an index is passed, then a random-access range is required.

index defaults to str.length if none is passed.

Returns:
The number of bytes in the UTF-16 sequence.

Throws:
May throw a UTFException if str[index] is not one past the end of a valid UTF-16 sequence.

Notes:
stride will only analize the element at str[index - 1] element. It will not fully verify the validity of UTF-16 sequence, nor even verify the presence of the sequence: it will not actually guarantee that stride(str, index) <= index.

uint stride(S)(auto ref S str, size_t index = 0);
stride returns the length of the UTF-32 sequence starting at index in str.

stride works with both UTF-32 strings and ranges of dchar.

Returns:
The number of bytes in the UTF-32 sequence (always 1).

Throws:
Never.

uint strideBack(S)(auto ref S str, size_t index);
uint strideBack(S)(auto ref S str);
strideBack returns the length of the UTF-32 sequence ending one code unit before index in str.

strideBack works with both UTF-32 strings and ranges of dchar. If no index is passed, then a bidirectional range will work, but if an index is passed, then a random-access range is required.

index defaults to str.length if none is passed.

Returns:
The number of bytes in the UTF-32 sequence (always 1).

Throws:
Never.

pure @safe size_t toUCSindex(C)(const(C)[] str, size_t index);
Given index into str and assuming that index is at the start of a UTF sequence, toUCSindex determines the number of UCS characters up to index. So, 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.

Examples:
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);

pure @safe size_t toUTFindex(in char[] str, size_t n);
pure nothrow @safe size_t toUTFindex(in wchar[] str, size_t n);
pure nothrow @safe size_t toUTFindex(in dchar[] str, size_t n);
Given a UCS index n into str, returns the UTF index. So, n is how many code points into the string the code point is, and the array index of the code unit is returned.

Examples:
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);

pure @trusted dchar decode(S)(auto ref S str, ref size_t index);
pure @trusted dchar decodeFront(S)(auto ref S str, out size_t index);
dchar decodeFront(S)(auto ref S str, out size_t index);
Decodes and returns the character starting at str[index]. index is advanced to one past the decoded character. If the character is not well-formed, then a UTFException is thrown and index remains unchanged.

decodeFront is a variant of decode which specifically decodes the first character.

decode will only work with strings and random access ranges of code units with length and slicing, whereas decodeFront will also work with any input range of code units.

Throws:
UTFException if str[index] is not the start of a valid UTF sequence.

pure @safe size_t encode(ref char[4u] buf, dchar c);
pure @safe size_t encode(ref wchar[2u] buf, dchar c);
Encodes c into the static array, buf, and returns the actual length of the encoded character (a number between 1 and 4 for char[4] buffers and a number between 1 and 2 for wchar[2] buffers).

Throws:
UTFException if c is not a valid UTF code point.

pure @safe void encode(ref char[] str, dchar c);
pure @safe void encode(ref wchar[] str, dchar c);
pure @safe void encode(ref dchar[] str, dchar c);
Encodes c in str's encoding and appends it to str.

Throws:
UTFException if c is not a valid UTF code point.

pure nothrow @safe ubyte codeLength(C)(dchar c);
Returns the number of code units that are required to encode the code point c when C is the character type used to encode it.

Examples:
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);

size_t codeLength(C, InputRange)(InputRange input);
Returns the number of code units that are required to encode str in a string whose character type is C. This is particularly useful when slicing one string with the length of another and the two string types use different character types.

Examples:
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.`);

pure @safe void validate(S)(in S str);
Checks to see if str is well-formed unicode or not.

Throws:
UTFException if str is not well-formed.

pure @safe string toUTF8(in char[] s);
pure @trusted string toUTF8(in wchar[] s);
pure @trusted string toUTF8(in dchar[] s);
Encodes string s into UTF-8 and returns the encoded string.

pure @trusted wstring toUTF16(in char[] s);
pure @safe wstring toUTF16(in wchar[] s);
pure @trusted wstring toUTF16(in dchar[] s);
Encodes string s into UTF-16 and returns the encoded string.

pure @trusted dstring toUTF32(in char[] s);
pure @trusted dstring toUTF32(in wchar[] s);
pure @safe dstring toUTF32(in dchar[] s);
Encodes string s into UTF-32 and returns the encoded string.

template toUTFz(P)
@system P toUTFz(P, S)(S str);
Returns a C-style zero-terminated string equivalent to str. str must not contain embedded '\0''s as any C function will treat the first '\0' that it sees as the end of the string. If str.empty is true, then a string containing only '\0' is returned.

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 char.

Warning 1: If the result of toUTFz equals str.ptr, then if anything alters the character one past the end of str (which is the '\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 str and no reallocation takes place or when 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 str. Another case where it could occur would be if you had a mutable character array immediately after 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 '\0'. Such scenarios will never occur if you immediately use the zero-terminated string after calling 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 '\0' to the string and use its ptr property rather than calling toUTFz.

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.

Examples:
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);

const(wchar)* toUTF16z(C)(const(C)[] str);
toUTF16z is a convenience function for toUTFz!(const(wchar)*).

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.

pure @trusted size_t count(C)(const(C)[] str);
Returns the total number of code points encoded in str.

Supercedes:
This function supercedes toUCSindex.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Throws:
UTFException if str is not well-formed.

Copyright Digital Mars 2000 - 2012. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.uuid

Category | Functions
Parsing UUIDs | parseUUID UUID(string) UUIDParsingException uuidRegex
Generating UUIDs | sha1UUID randomUUID md5UUID
Using UUIDs | UUID.uuidVersion UUID.variant UUID.toString UUID.data UUID.swap UUID.opEquals UUID.opCmp UUID.toHash
UUID namespaces | dnsNamespace urlNamespace oidNamespace x500Namespace

A UUID, or 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.

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 UUID.empty is true. Empty UUIDs are equal to 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 boost.uuid from the Boost project with some minor additions and API changes for a more D-like API.

Examples:
 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);

Standards:
RFC 4122

See Also:
http://en.wikipedia.org/wiki/Universally_unique_identifier

License:
Boost License 1.0

Authors:
Johannes Pfau

Source:
std/uuid.d

struct UUID;

enum Variant;
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 std.variant.Variant. This has nothing to do with std.variant.Variant.

ncs
NCS backward compatibility

rfc4122
Defined in RFC 4122 document

microsoft
Microsoft Corporation backward compatibility

future
Reserved for future use

enum Version;
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 std.uuid, but only version 3, 4 and 5 UUIDs can be generated.

unknown
Unknown version

timeBased
Version 1

dceSecurity
Version 2

nameBasedMD5
Version 3 (Name based + MD5)

randomNumberBased
Version 4 (Random)

nameBasedSHA1
Version 5 (Name based + SHA-1)

ubyte[16] data;
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.

Examples:
 auto rawData = uuid.data; //get data
 rawData[0] = 1; //modify
 uuid.data = rawData; //set data
 uuid.data[1] = 2; //modify directly

this()(ubyte[16] uuidData);
Construct a UUID struct from the 16 byte representation of a UUID.

Examples:
 ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
 auto tmp = UUID(data);
 assert(tmp.data == data);

this(T)(T[] uuid);
Parse a UUID from its canonical string form. An UUID in its canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46

Throws:
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 parseUUID

Examples:
 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!

BUGS:
Could be pure, but this depends on parse!(string, 16).

const pure nothrow @property @trusted bool empty();
Returns true if and only if the UUID is equal to {00000000-0000-0000-0000-000000000000}

Examples:
 UUID id;
 assert(id.empty);
 id = UUID("00000000-0000-0000-0000-000000000001");
 assert(!id.empty);

const pure nothrow @property @safe Variant variant();
RFC 4122 defines different internal data layouts for UUIDs. Returns the format used by this UUID.

Note:
Do not confuse this with std.variant.Variant. This has nothing to do with std.variant.Variant. The type of this property is std.uuid.UUID.Variant.

See Also:
UUID.Variant

Examples:
 assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant
     == UUID.Variant.rfc4122);

const pure nothrow @property @safe Version uuidVersion();
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:
UUID.Version

Examples:
  assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion
      == UUID.Version.randomNumberBased);

nothrow @safe void swap(ref UUID rhs);
Swap the data of this UUID with the data of rhs.

Note:
linear complexity

Examples:
 UUID u1;
 auto u2 = UUID(cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
 u1.swap(u2);

 assert(u1.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
 assert(u2.data == cast(ubyte[16])[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);

const pure nothrow @safe bool opEquals(const UUID s);
const pure nothrow @safe bool opEquals(ref const UUID s);
const pure nothrow @safe int opCmp(ref const UUID s);
const pure nothrow @safe int opCmp(const UUID s);
const pure nothrow @safe size_t toHash();
All of the standard numeric operators are defined for the UUID struct.

Examples:
 //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);

const void toString(scope void delegate(const(char)[]) sink);
const pure nothrow @safe string toString();
Return the UUID as a string in the canonical form.

Examples:
 auto id = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");

pure @safe UUID md5UUID(const(char[]) name, const UUID namespace = (UUID).init);
pure @trusted UUID md5UUID(const(ubyte[]) data, const UUID namespace = (UUID).init);
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 UUID.init is used.

Note:
The default namespaces (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.

Examples:
 //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);

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 std.uuid is compatible with Boost's implementation. 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!).

pure @trusted UUID sha1UUID(const(char[]) name, const UUID namespace = (UUID).init);
pure @trusted UUID sha1UUID(const(ubyte[]) data, const UUID namespace = (UUID).init);
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 UUID.init is used.

Note:
The default namespaces (dnsNamespace, ...) defined by this module should be used when appropriate.

CTFE:
CTFE is not supported.

Examples:
 //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);

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 std.uuid is compatible with Boost's implementation. 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!).

UUID randomUUID()();
UUID randomUUID(RNG)(ref RNG randomGen);
This function generates a random number based UUID from a random number generator.

CTFE:
This function is not supported at compile time.

Examples:
 //simple call
 auto uuid = randomUUID();

 //provide a custom RNG. Must be seeded manually.
 Xorshift192 gen;

 gen.seed(unpredictableSeed);
 auto uuid3 = randomUUID(gen);

UUID parseUUID(T)(T uuidString);
UUID parseUUID(Range)(ref Range uuidRange);
This is a less strict parser compared to the parser used in the UUID constructor. It enforces the following rules:

  • hex numbers are always two hexdigits([0-9a-fA-F])
  • there must be exactly 16 such pairs in the input, not less, not more
  • there can be exactly one dash between two hex-pairs, but not more
  • there can be multiple characters enclosing the 16 hex pairs, as long as these characters do not contain [0-9a-fA-F]

Throws:
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.

Examples:
 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!

BUGS:
Could be pure, but this depends on parse!(string, 16).

UUID dnsNamespace;
Default namespace from RFC 4122

Name string is a fully-qualified domain name

UUID urlNamespace;
Default namespace from RFC 4122

Name string is a URL

UUID oidNamespace;
Default namespace from RFC 4122

Name string is an ISO OID

UUID x500Namespace;
Default namespace from RFC 4122

Name string is an X.500 DN (in DER or a text output format)

string uuidRegex;
Regex string to extract UUIDs from text.

Examples:
 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);
 }

 writeln(found);

class UUIDParsingException: object.Exception;
This exception is thrown if an error occurs when parsing a UUID from a string.

enum Reason;
Reason reason;
The reason why parsing the UUID string failed (if known)

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

string input;
The original input string which should have been parsed.

size_t position;
The position in the input string where the error occurred.

Copyright Johannes Pfau 2011 - . | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.variant

This module implements a discriminated union type (a.k.a. tagged union, algebraic type). Such types are useful for type-uniform binary interfaces, interfacing with scripting languages, and comfortable exploratory programming.

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

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.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Source:
std/variant.d

struct VariantN(size_t maxDataSize, AllowedTypesX...);
VariantN is a back-end type seldom used directly by user code. Two commonly-used types using VariantN as back-end are:

  1. Algebraic: A closed discriminated union with a limited type universe (e.g., Algebraic!(int, double, string) only accepts these three types and rejects anything else).
  2. Variant: An open discriminated union allowing an unbounded set of types. The restriction is that the size of the stored type cannot be larger than the largest built-in type. This means that Variant can accommodate all primitive types and all user-defined types except for large structs.

Both Algebraic and Variant share VariantN's interface. (See their respective documentations below.)

VariantN is a discriminated union type parameterized with the largest size of the types stored (maxDataSize) and with the list of allowed types (AllowedTypes). If the list is empty, then any type up of size up to maxDataSize (rounded up for alignment) can be stored in a VariantN object.

template allowed(T)
Tells whether a type T is statically allowed for storage inside a VariantN object by looking T up in AllowedTypes. If AllowedTypes is empty, all types of size up to maxSize are allowed.

this(T)(T value);
Constructs a VariantN value given an argument of a generic type. Statically rejects disallowed types.

VariantN opAssign(T)(T rhs);
Assigns a VariantN from a generic argument. Statically rejects disallowed types.

const pure nothrow bool hasValue();
Returns true if and only if the VariantN object holds a valid value (has been initialized with, or assigned from, a valid value).

Example:
 Variant a;
 assert(!a.hasValue);
 Variant b;
 a = b;
 assert(!a.hasValue); // still no value
 a = 5;
 assert(a.hasValue);

T* peek(T)();
If the VariantN object holds a value of the exact type T, returns a pointer to that value. Otherwise, returns null. In cases where T is statically disallowed, peek will not compile.

Example:
 Variant a = 5;
 auto b = a.peek!(int);
 assert(b !is null);
 *b = 6;
 assert(a == 6);

const TypeInfo type();
Returns the typeid of the currently held value.

const bool convertsTo(T)();
Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.

T get(T)();
Returns the value stored in the VariantN object, implicitly converted to the requested type T, in fact DecayStaticToDynamicArray!(T). If an implicit conversion is not possible, throws a VariantException.

T coerce(T)();
Returns the value stored in the VariantN object, explicitly converted (coerced) to the requested type T. If T is a string type, the value is formatted as a string. If the VariantN object is a string, a parse of the string to type T is attempted. If a conversion is not possible, throws a VariantException.

string toString();
Formats the stored value as a string.

bool opEquals(T)(T rhs);
Comparison for equality used by the "==" and "!=" operators.

int opCmp(T)(T rhs);
Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.

size_t toHash();
Computes the hash of the held value.

VariantN opAdd(T)(T rhs);
VariantN opSub(T)(T rhs);
Arithmetic between VariantN objects and numeric values. All arithmetic operations return a VariantN object typed depending on the types of both values involved. The conversion rules mimic D's built-in rules for arithmetic conversions.

VariantN opMul(T)(T rhs);
VariantN opDiv(T)(T rhs);
VariantN opMod(T)(T rhs);
VariantN opAnd(T)(T rhs);
VariantN opOr(T)(T rhs);
VariantN opXor(T)(T rhs);
VariantN opShl(T)(T rhs);
VariantN opShr(T)(T rhs);
VariantN opUShr(T)(T rhs);
VariantN opCat(T)(T rhs);
VariantN opAddAssign(T)(T rhs);
VariantN opSubAssign(T)(T rhs);
VariantN opMulAssign(T)(T rhs);
VariantN opDivAssign(T)(T rhs);
VariantN opModAssign(T)(T rhs);
VariantN opAndAssign(T)(T rhs);
VariantN opOrAssign(T)(T rhs);
VariantN opXorAssign(T)(T rhs);
VariantN opShlAssign(T)(T rhs);
VariantN opShrAssign(T)(T rhs);
VariantN opUShrAssign(T)(T rhs);
VariantN opCatAssign(T)(T rhs);
ditto ditto

VariantN opIndex(K)(K i);
VariantN opIndexAssign(T, N)(T value, N i);
Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.

Example:
 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 op= will not work properly:

 Variant a = new int[10];
 a[5] = 42;
 a[5] += 8;
 assert(a[5] == 50); // fails, a[5] is still 42

size_t length();
If the VariantN contains an (associative) array, returns the length of that array. Otherwise, throws an exception.

int opApply(Delegate)(scope Delegate dg);
If the VariantN contains an array, applies dg to each element of the array in turn. Otherwise, throws an exception.

template Algebraic(T...)
Algebraic data type restricted to a closed set of possible types. It's an alias for a 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.

Future additions to Algebraic will allow compile-time checking that all possible types are handled by user code, eliminating a large class of errors.

BUGS:
Currently, Algebraic does not allow recursive data types. They will be allowed in a future iteration of the implementation.

Example:
 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

alias VariantN!(20u).VariantN Variant;
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, including all numeric types, pointers, delegates, and class references. You may want to use VariantN directly with a different maximum size either for storing larger types, or for saving memory.

Variant[] variantArray(T...)(T args);
Returns an array of variants constructed from args.

Example:
 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 boxArray function in the std.boxer module can achieve it like this:

 // old
 Box[] fun(...)
 {
     ...
     return boxArray(_arguments, _argptr);
 }
 // new
 Variant[] fun(T...)(T args)
 {
     ...
     return variantArray(args);
 }

This is by design. During construction the Variant needs static type information about the type being held, so as to store a pointer to function for fast retrieval.

class VariantException: object.Exception;
Thrown in three cases:

  1. An uninitialized Variant is used in any way except assignment and hasValue;
  2. A get or coerce is attempted with an incompatible target type;
  3. A comparison between Variant objects of incompatible types is attempted.

TypeInfo source;
The source type in the conversion or comparison

TypeInfo target;
The target type in the conversion or comparison

template visit(Handler...) if (Handler.length > 0)
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 's current value. Visiting handlers are passed in the template parameter list. It is statically ensured that all types of variant are handled accross all handlers. 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.

Example:
   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) => return i,
                         (string s) => cast(int)s.length)()
                         == 6);

   // Error function usage
   Algebraic!(int, string) emptyVar;
   assert(variant.visit!((string s) => cast(int)s.length,
                         (int i)    => i,
                         () => -1)()
                         == -1);

Returns:
The return type of visit is deduced from the visiting functions and must be the same accross all overloads.

Throws:
If no parameter-less, error function is specified: VariantException if variant doesn't hold a value.

template tryVisit(Handler...) if (Handler.length > 0)
Behaves as 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 variant doesn't hold a value or holds a type which isn't handled by the visiting functions.

Example:
   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);

Returns:
The return type of tryVisit is deduced from the visiting functions and must be the same accross all overloads.

Throws:
If no parameter-less, error function is specified: VariantException if variant doesn't hold a value or if variant holds a value which isn't handled by the visiting functions.

Copyright Andrei Alexandrescu 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.xml

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

License:
Boost License 1.0.

Authors:
Janice Caron

Source:
std/xml.d

bool isChar(dchar c);
Returns true if the character is a character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isSpace(dchar 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:
XML 1.0

Parameters:
dchar c the character to be tested

bool isDigit(dchar c);
Returns true if the character is a digit according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isLetter(dchar c);
Returns true if the character is a letter according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isIdeographic(dchar c);
Returns true if the character is an ideographic character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isBaseChar(dchar c);
Returns true if the character is a base character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isCombiningChar(dchar c);
Returns true if the character is a combining character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isExtender(dchar c);
Returns true if the character is an extender according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

S encode(S)(S s);
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:
XML 1.0

Parameters:
s The string to be encoded

Returns:
The encoded string

Examples:
 writefln(encode("a > b")); // writes "a &gt; b"

enum DecodeMode;
Mode to use for decoding.

NONE
Do not decode
LOOSE
Decode, but ignore errors
STRICT
Decode, and throw exception on error

string decode(string s, DecodeMode mode = (DecodeMode).LOOSE);
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:
XML 1.0

Parameters:
string s | The string to be decoded
DecodeMode mode | (optional) Mode to use for decoding. (Defaults to LOOSE).

Throws:
DecodeException if mode == DecodeMode.STRICT and decode fails

Returns:
The decoded string

Examples:
 writefln(decode("a &gt; b")); // writes "a > b"

class Document: std.xml.Element;
Class representing an XML document.

Standards:
XML 1.0

string prolog;
Contains all text which occurs before the root element. Defaults to <?xml version="1.0"?>

string epilog;
Contains all text which occurs after the root element. Defaults to the empty string

this(string s);
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.

Parameters:
string s the complete XML text.

this(const(Tag) tag);
Constructs a Document from a Tag.

Parameters:
const(Tag) tag the start tag of the document.

const const bool opEquals(Object o);
Compares two Documents for equality

Examples:
 Document d1,d2;
 if (d1 == d2) { }

const const int opCmp(Object o);
Compares two Documents

You should rarely need to call this function. It exists so that Documents can be used as associative array keys.

Examples:
 Document d1,d2;
 if (d1 < d2) { }

const const nothrow @trusted size_t toHash();
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.

const const string toString();
Returns the string representation of a Document. (That is, the complete XML of a document).

class Element: std.xml.Item;
Class representing an XML element.

Standards:
XML 1.0

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

this(string name, string interior = null);
Constructs an Element given a name and a string to be used as a Text interior.

Parameters:
string name | the name of the element.
string interior | (optional) the string interior.

Examples:
 auto element = new Element("title","Serenity")
     // constructs the element <title>Serenity</title>

this(const(Tag) tag_);
Constructs an Element from a Tag.

Parameters:
tag the start or empty tag of the element.

void opCatAssign(Text item);
Append a text item to the interior of this element

Parameters:
Text item the item you wish to append.

Examples:
 Element element;
 element ~= new Text("hello");

void opCatAssign(CData item);
Append a CData item to the interior of this element

Parameters:
CData item the item you wish to append.

Examples:
 Element element;
 element ~= new CData("hello");

void opCatAssign(Comment item);
Append a comment to the interior of this element

Parameters:
Comment item the item you wish to append.

Examples:
 Element element;
 element ~= new Comment("hello");

void opCatAssign(ProcessingInstruction item);
Append a processing instruction to the interior of this element

Parameters:
ProcessingInstruction item the item you wish to append.

Examples:
 Element element;
 element ~= new ProcessingInstruction("hello");

void opCatAssign(Element item);
Append a complete element to the interior of this element

Parameters:
Element item the item you wish to append.

Examples:
 Element element;
 Element other = new Element("br");
 element ~= other;
    // appends element representing <br />

bool opEquals(Object o);
Compares two Elements for equality

Examples:
 Element e1,e2;
 if (e1 == e2) { }

int opCmp(Object o);
Compares two Elements

You should rarely need to call this function. It exists so that Elements can be used as associative array keys.

Examples:
 Element e1,e2;
 if (e1 < e2) { }

const const nothrow @safe size_t toHash();
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.

const const string text(DecodeMode mode = (DecodeMode).LOOSE);
Returns the decoded interior of an element.

The element is assumed to containt text only. So, for example, given XML such as "<title>Good &amp; Bad</title>", will return "Good & Bad".

Parameters:
DecodeMode mode (optional) Mode to use for decoding. (Defaults to LOOSE).

Throws:
DecodeException if decode fails

const const string[] pretty(uint indent = 2);
Returns an indented string representation of this item

Parameters:
uint indent (optional) number of spaces by which to indent this element. Defaults to 2.

const const string toString();
Returns the string representation of an Element

Examples:
 auto element = new Element("br");
 writefln(element.toString()); // writes "<br />"

enum TagType;
Tag types.

START
Used for start tags
END
Used for end tags
EMPTY
Used for empty tags

class Tag;
Class representing an XML tag.

Standards:
XML 1.0

The class invariant guarantees
  • that type is a valid enum TagType value
  • that name consists of valid characters
  • that each attribute name consists of valid characters

TagType type;
Type of tag

string name;
Tag name

string[string] attr;
Associative array of attributes

this(string name, TagType type = TagType.START);
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 attr member variable.

Parameters:
string name | the Tag's name
TagType type | (optional) the Tag's type. If omitted, defaults to TagType.START.

Examples:
 auto tag = new Tag("img",Tag.EMPTY);
 tag.attr["src"] = "http://example.com/example.jpg";

const const bool opEquals(Object o);
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.

Examples:
 Tag tag1,tag2
 if (tag1 == tag2) { }

const const int opCmp(Object o);
Compares two Tags

Examples:
 Tag tag1,tag2
 if (tag1 < tag2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns the string representation of a Tag

Examples:
 auto tag = new Tag("book",TagType.START);
 writefln(tag.toString()); // writes "<book>"

const const @property bool isStart();
Returns true if the Tag is a start tag

Examples:
 if (tag.isStart) { }

const const @property bool isEnd();
Returns true if the Tag is an end tag

Examples:
 if (tag.isEnd) { }

const const @property bool isEmpty();
Returns true if the Tag is an empty tag

Examples:
 if (tag.isEmpty) { }

class Comment: std.xml.Item;
Class representing a comment

this(string content);
Construct a comment

Parameters:
string content the body of the comment

Throws:
CommentException if the comment body is illegal (contains "--" or exactly equals "-")

Examples:
 auto item = new Comment("This is a comment");
    // constructs <!--This is a comment-->

bool opEquals(Object o);
Compares two comments for equality

Examples:
 Comment item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two comments

You should rarely need to call this function. It exists so that Comments can be used as associative array keys.

Examples:
 Comment item1,item2;
 if (item1 < item2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns a string representation of this comment

const const @property bool isEmptyXML();
Returns false always

class CData: std.xml.Item;
Class representing a Character Data section

this(string content);
Construct a chraracter data section

Parameters:
string content the body of the character data segment

Throws:
CDataException if the segment body is illegal (contains "]]>")

Examples:
 auto item = new CData("<b>hello</b>");
    // constructs <![CDATA[<b>hello</b>]]>

bool opEquals(Object o);
Compares two CDatas for equality

Examples:
 CData item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two CDatas

You should rarely need to call this function. It exists so that CDatas can be used as associative array keys.

Examples:
 CData item1,item2;
 if (item1 < item2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns a string representation of this CData section

const const @property bool isEmptyXML();
Returns false always

class Text: std.xml.Item;
Class representing a text (aka Parsed Character Data) section

this(string content);
Construct a text (aka PCData) section

Parameters:
string content the text. This function encodes the text before insertion, so it is safe to insert any text

Examples:
 auto Text = new CData("a < b");
    // constructs a &lt; b

bool opEquals(Object o);
Compares two text sections for equality

Examples:
 Text item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two text sections

You should rarely need to call this function. It exists so that Texts can be used as associative array keys.

Examples:
 Text item1,item2;
 if (item1 < item2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns a string representation of this Text section

const const @property bool isEmptyXML();
Returns true if the content is the empty string

class XMLInstruction: std.xml.Item;
Class representing an XML Instruction section

this(string content);
Construct an XML Instruction section

Parameters:
string content the body of the instruction segment

Throws:
XIException if the segment body is illegal (contains ">")

Examples:
 auto item = new XMLInstruction("ATTLIST");
    // constructs <!ATTLIST>

bool opEquals(Object o);
Compares two XML instructions for equality

Examples:
 XMLInstruction item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two XML instructions

You should rarely need to call this function. It exists so that XmlInstructions can be used as associative array keys.

Examples:
 XMLInstruction item1,item2;
 if (item1 < item2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns a string representation of this XmlInstruction

const const @property bool isEmptyXML();
Returns false always

class ProcessingInstruction: std.xml.Item;
Class representing a Processing Instruction section

this(string content);
Construct a Processing Instruction section

Parameters:
string content the body of the instruction segment

Throws:
PIException if the segment body is illegal (contains "?>")

Examples:
 auto item = new ProcessingInstruction("php");
    // constructs <?php?>

bool opEquals(Object o);
Compares two processing instructions for equality

Examples:
 ProcessingInstruction item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two processing instructions

You should rarely need to call this function. It exists so that ProcessingInstructions can be used as associative array keys.

Examples:
 ProcessingInstruction item1,item2;
 if (item1 < item2) { }

const const nothrow @safe size_t toHash();
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.

const const string toString();
Returns a string representation of this ProcessingInstruction

const const @property bool isEmptyXML();
Returns false always

abstract class Item;
Abstract base class for XML items

abstract bool opEquals(Object o);
Compares with another Item of same type for equality

abstract int opCmp(Object o);
Compares with another Item of same type

abstract const const nothrow @safe size_t toHash();
Returns the hash of this item

abstract const const string toString();
Returns a string representation of this item

const const string[] pretty(uint indent);
Returns an indented string representation of this item

Parameters:
uint indent number of spaces by which to indent child elements

abstract const const @property bool isEmptyXML();
Returns true if the item represents empty XML text

class DocumentParser: std.xml.ElementParser;
Class for parsing an XML Document.

This is a subclass of ElementParser. Most of the useful functions are documented there.

Standards:
XML 1.0

BUGS:
Currently only supports UTF documents.

If there is an encoding attribute in the prolog, it is ignored.

this(string xmlText_);
Constructs a DocumentParser.

The input to this function MUST be valid XML. This is enforced by the function's in contract.

Parameters:
xmltext the entire XML document as text

class ElementParser;
Class for parsing an XML element.

Standards:
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.

const const @property const(Tag) tag();
The Tag at the start of the element being parsed. You can read this to determine the tag's name and attributes.

ParserHandler[string] onStartTag;
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.

Examples:
 // Call this function whenever a <podcast> 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 <episode>
 // 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/>.

ElementHandler[string] onEndTag;
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.

Examples:
 // Call this function whenever a </podcast> 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 </episode>
 // 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/>.

@property void onText(Handler handler);
Register a handler which will be called whenever text is encountered.

Examples:
 // 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
 };

void onTextRaw(Handler handler);
Register an alternative handler which will be called whenever text is encountered. This differs from onText in that onText will decode the text, wheras 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.

Examples:
 // 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
 };

@property void onCData(Handler handler);
Register a handler which will be called whenever a character data segement is encountered.

Examples:
 // Call this function whenever a CData section is encountered
 onCData = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <![CDATA[
     // nor closing ]]>
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

@property void onComment(Handler handler);
Register a handler which will be called whenever a comment is encountered.

Examples:
 // Call this function whenever a comment is encountered
 onComment = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <!-- nor
     // closing -->
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

@property void onPI(Handler handler);
Register a handler which will be called whenever a processing instruction is encountered.

Examples:
 // Call this function whenever a processing instruction is encountered
 onPI = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <? nor
     // closing ?>
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

@property void onXI(Handler handler);
Register a handler which will be called whenever an XML instruction is encountered.

Examples:
 // Call this function whenever an XML instruction is encountered
 // (Note: XML instructions may only occur preceeding the root tag of a
) // document.
 onPI = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <! nor
     // closing >
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void parse();
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

const const string toString();
Returns that part of the element which has already been parsed

void check(string s);
Check an entire XML document for well-formedness

Parameters:
string s the document to be checked, passed as a string

Throws:
CheckException if the document is not well formed

CheckException's toString() method will yield the complete heirarchy of parse failure (the XML equivalent of a stack trace), giving the line and column number of every failure at every level.

class XMLException: object.Exception;
The base class for exceptions thrown by this module

class CommentException: std.xml.XMLException;
Thrown during Comment constructor

class CDataException: std.xml.XMLException;
Thrown during CData constructor

class XIException: std.xml.XMLException;
Thrown during XMLInstruction constructor

class PIException: std.xml.XMLException;
Thrown during ProcessingInstruction constructor

class TextException: std.xml.XMLException;
Thrown during Text constructor

class DecodeException: std.xml.XMLException;
Thrown during decode()

class InvalidTypeException: std.xml.XMLException;
Thrown if comparing with wrong type

class TagException: std.xml.XMLException;
Thrown when parsing for Tags

class CheckException: std.xml.XMLException;
Thrown during check()

CheckException err;
Parent in heirarchy

string msg;
Name of production rule which failed to parse, or specific error message

size_t line;
Line number at which parse failure occurred

size_t column;
Column number at which parse failure occurred

Copyright Janice Caron 2008 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.zip

Read/write data in the zip archive format. Makes use of the etc.c.zlib compression library.

BUGS:
  • Multi-disk zips not supported.
  • Only Zip version 20 formats are supported.
  • Only supports compression modes 0 (no compression) and 8 (deflate).
  • Does not support encryption.
  • Bugzilla 592
  • Bugzilla 1832
  • Bugzilla 2137
  • Bugzilla 2138

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/zip.d

class ZipException: object.Exception;
Thrown on error.

class ArchiveMember;
A member of the ZipArchive.

ushort madeVersion;
Read Only

ushort extractVersion;
Read Only

ushort flags;
Read/Write: normally set to 0

ushort compressionMethod;
Read/Write: 0 for compression, 8 for deflate

std.datetime.DosFileTime time;
Read/Write: Last modified time of the member. It's in the DOS date/time format.

uint crc32;
Read Only: cyclic redundancy check (CRC) value

uint compressedSize;
Read Only: size of data of member in compressed form.

uint expandedSize;
Read Only: size of data of member in expanded form.

ushort diskNumber;
Read Only: should be 0.

ushort internalAttributes;
Read/Write

uint externalAttributes;
Read/Write

string name;
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.

ubyte[] extra;
Read/Write: extra data for this member.

string comment;
Read/Write: comment associated with this member.

ubyte[] compressedData;
Read Only: data of member in compressed form.

ubyte[] expandedData;
Read/Write: data of member in uncompressed form.

class ZipArchive;
Object representing the entire archive. ZipArchives are collections of ArchiveMembers.

ubyte[] data;
Read Only: array representing the entire contents of the archive.

uint diskNumber;
Read Only: 0 since multi-disk zip archives are not supported.

uint diskStartDir;
Read Only: 0 since multi-disk zip archives are not supported.

uint numEntries;
Read Only: number of ArchiveMembers in the directory.

uint totalEntries;
Read Only: same as totalEntries.

string comment;
Read/Write: the archive comment. Must be less than 65536 bytes in length.

ArchiveMember[string] directory;
Read Only: array indexed by the name of each member of the archive.

Example:
All the members of the archive can be accessed with a foreach loop:
 ZipArchive archive = new ZipArchive(data);
 foreach (ArchiveMember am; archive.directory)
 {
     writefln("member name is '%s'", am.name);
 }

this();
Constructor to use when creating a new archive.

void addMember(ArchiveMember de);
Add de to the archive.

void deleteMember(ArchiveMember de);
Delete de from the archive.

void[] build();
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.

this(void[] buffer);
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.

Parameters:
void[] buffer the entire contents of the archive.

ubyte[] expand(ArchiveMember de);
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[].

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.zlib

Compress/decompress data using the zlib library.

References:
Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/zlib.d

class ZlibException: object.Exception;
Errors throw a ZlibException.

uint adler32(uint adler, const(void)[] buf);
Compute the Adler32 checksum of the data in buf[]. adler is the starting value when computing a cumulative checksum.

uint crc32(uint crc, const(void)[] buf);
Compute the CRC32 checksum of the data in buf[]. crc is the starting value when computing a cumulative checksum.

const(void)[] compress(const(void)[] srcbuf, int level);
const(void)[] compress(const(void)[] buf);
Compresses the data in srcbuf[] using compression level level. The default value for level is 6, legal values are 1..9, with 1 being the least compression and 9 being the most. Returns the compressed data.

void[] uncompress(void[] srcbuf, size_t destlen = 0u, int winbits = 15);
Decompresses the data in srcbuf[].

Parameters:
size_t destlen size of the uncompressed data. It need not be accurate, but the decompression will be faster if the exact size is supplied.

Returns:
the decompressed data.

enum HeaderFormat;
the header format the compressed stream is wrapped in

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

class Compress;
Used when the data to be compressed is not all in one buffer.

this(int level, HeaderFormat header = HeaderFormat.deflate);
this(HeaderFormat header = HeaderFormat.deflate);
Construct. level is the same as for D.zlib.compress(). header can be used to make a gzip compatible stream.

const(void)[] compress(const(void)[] buf);
Compress the data in buf and return the compressed data. The buffers returned from successive calls to this should be concatenated together.

void[] flush(int mode = Z_FINISH);
Compress and return any remaining data. The returned data should be appended to that returned by compress().

Parameters:
int mode one of the following:
Z_SYNC_FLUSH
Syncs up flushing to the next byte boundary. Used when more data is to be compressed later on.
Z_FULL_FLUSH
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.
Z_FINISH
(default) Used when finished compressing the data.

class UnCompress;
Used when the data to be decompressed is not all in one buffer.

this(uint destbufsize);
this(HeaderFormat format = HeaderFormat.determineFromData);
Construct. destbufsize is the same as for D.zlib.uncompress().

const(void)[] uncompress(const(void)[] buf);
Decompress the data in buf and return the decompressed data. The buffers returned from successive calls to this should be concatenated together.

void[] flush();
Decompress and return any remaining data. The returned data should be appended to that returned by uncompress(). The UnCompress object cannot be used further.

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.net.curl

Category | Functions
High level | download upload get post put del options trace connect byLine byChunk byLineAsync byChunkAsync
Low level | HTTP FTP SMTP

Networking client functionality as provided by libcurl. The libcurl library must be installed on the system in order to use this module.

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 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 byLineAsync and byChunkAsync provides asynchronous 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.

Cheat Sheet
Function Name | Description
High level
download | download("ftp.digitalmars.com/sieve.ds", "/tmp/downloaded-ftp-file") downloads file from URL to file system.
upload | upload("/tmp/downloaded-ftp-file", "ftp.digitalmars.com/sieve.ds"); uploads file from file system to URL.
get | get("dlang.org") returns a string containing the dlang.org web page.
put | put("dlang.org", "Hi") returns a string containing the dlang.org web page. after a HTTP PUT of "hi"
post | post("dlang.org", "Hi") returns a string containing the dlang.org web page. after a HTTP POST of "hi"
byLine | byLine("dlang.org") returns a range of strings containing the dlang.org web page.
byChunk | byChunk("dlang.org", 10) returns a range of ubyte[10] containing the dlang.org web page.
byLineAsync | byLineAsync("dlang.org") returns a range of strings containing the dlang.org web page asynchronously.
byChunkAsync | byChunkAsync("dlang.org", 10) returns a range of ubyte[10] containing the dlang.org web page asynchronously.
Low level
HTTP | HTTP struct for advanced usage
FTP | FTP struct for advanced usage
SMTP | SMTP struct for advanced usage

Example:
import std.net.curl, std.stdio;

// Return a string containing the content specified by an URL
string content = get("dlang.org");

// Post data and return a string containing the content specified by an URL
string content = post("mydomain.com/here.cgi", "post data");

// Get content of file from ftp server
string 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 writting 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 onReceiveHeader/onReceive for more information. Finally the HTTP request is effected by calling perform(), which is synchronous.

Source:
std/net/curl.d

License:
Boost License 1.0.

Authors:
Jonas Drewsen. Some of the SMTP code contributed by Jimmy Cao.

Credits:
The functionally is based on libcurl. LibCurl is licensed under an MIT/X derivate license.

struct AutoProtocol;
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");

void download(Conn = AutoProtocol)(const(char)[] url, string saveToPath, Conn conn = Conn());
HTTP/FTP download to local file system.

Parameters:
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("ftp.digitalmars.com/sieve.ds", "/tmp/downloaded-ftp-file");
 download("d-lang.appspot.com/testUrl2", "/tmp/downloaded-http-file");

void upload(Conn = AutoProtocol)(string loadFromPath, const(char)[] url, Conn conn = Conn());
Upload file from local files system using the HTTP or FTP protocol.

Parameters:
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");

T[] get(Conn = AutoProtocol, T = char)(const(char)[] url, Conn conn = Conn());
HTTP/FTP get content.

Parameters:
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 T specifies the type to return. Possible values are char and ubyte to return char[] or ubyte[].

Example:
 import std.net.curl;
 string content = get("d-lang.appspot.com/testUrl2");

Returns:
A T[] range containing the content of the resource pointed to by the URL.

See Also:
HTTP.Method

T[] post(T = char, PostUnit)(const(char)[] url, const(PostUnit)[] postData, HTTP conn = HTTP());
HTTP post content.

Parameters:
url | resource to post to
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 T specifies the type to return. Possible values are char and ubyte to return char[] or ubyte[].

Example:
 import std.net.curl;
 string 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:
HTTP.Method

T[] put(Conn = AutoProtocol, T = char, PutUnit)(const(char)[] url, const(PutUnit)[] putData, Conn conn = Conn());
HTTP/FTP put content.

Parameters:
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 T specifies the type to return. Possible values are char and ubyte to return char[] or ubyte[].

Example:
 import std.net.curl;
 string 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:
HTTP.Method

void del(Conn = AutoProtocol)(const(char)[] url, Conn conn = Conn());
HTTP/FTP delete content.

Parameters:
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:
HTTP.Method

T[] options(T = char, OptionsUnit)(const(char)[] url, const(OptionsUnit)[] optionsData = null, HTTP conn = HTTP());
HTTP options request.

Parameters:
url | resource make a option call to
optionsData | options 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 T specifies the type to return. Possible values are char and ubyte to return char[] or ubyte[]. Currently the HTTP RFC does not specify any usage of the optionsData and for this reason the example below does not send optionsData to the server.

Example:
 import std.net.curl;
 auto http = HTTP();
 options("d-lang.appspot.com/testUrl2", null, 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:
HTTP.Method

T[] trace(T = char)(const(char)[] url, HTTP conn = HTTP());
HTTP trace request.

Parameters:
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 T specifies the type to return. Possible values are char and ubyte to return char[] or 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:
HTTP.Method

T[] connect(T = char)(const(char)[] url, HTTP conn = HTTP());
HTTP connect request.

Parameters:
url resource make a connect 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 T specifies the type to return. Possible values are char and ubyte to return char[] or 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:
HTTP.Method

auto byLine(Conn = AutoProtocol, Terminator = char, Char = char)(const(char)[] url, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\x0a', Conn conn = Conn());
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 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);

Parameters:
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
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 byChunk(Conn = AutoProtocol)(const(char)[] url, size_t chunkSize = 1024, Conn conn = Conn());
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 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]

Parameters:
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 byLineAsync(Conn = AutoProtocol, Terminator = char, Char = char, PostUnit)(const(char)[] url, const(PostUnit)[] postData, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\x0a', size_t transmitBuffers = 10, Conn conn = Conn());
auto byLineAsync(Conn = AutoProtocol, Terminator = char, Char = char)(const(char)[] url, KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\x0a', size_t transmitBuffers = 10, Conn conn = Conn());
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 conn parameter with a HTTP/FTP instance that has these properties set.

If postData is non-null the method will be set to 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 wait(Duration) method on the 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!");

Parameters:
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 byChunkAsync(Conn = AutoProtocol, PostUnit)(const(char)[] url, const(PostUnit)[] postData, size_t chunkSize = 1024, size_t transmitBuffers = 10, Conn conn = Conn());
auto byChunkAsync(Conn = AutoProtocol)(const(char)[] url, size_t chunkSize = 1024, size_t transmitBuffers = 10, Conn conn = Conn());
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 conn parameter with a HTTP/FTP instance that has these properties set.

If postData is non-null the method will be set to 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 wait(Duration) method on the 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!");

Parameters:
url | The url to receive content from
postData | Data to HTTP Post
terminator | The character that terminates a line
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.

struct HTTP;
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 = (double dltotal, double dlnow,
                    double ultotal, double ulnow)
 {
     writeln("Progress ", dltotal, ", ", dlnow, ", ", ultotal, ", ", ulnow);
     return 0;
 };
 http.perform();

See Also:
RFC2616

alias etc.c.curl.CurlAuth AuthMethod;
Authentication method equal to etc.c.curl.CurlAuth

alias etc.c.curl.CurlTimeCond TimeCond;
Time condition enumeration as an alias of etc.c.curl.CurlTimeCond

RFC2616 Section 14.25

this(const(char)[] url);
Constructor taking the url as parameter.

void perform();
Perform a http request.

After the HTTP client has been setup and possibly assigned callbacks the perform() method will start performing the request towards the specified server.

@property void url(const(char)[] url);
The URL to specify the location of the resource.

alias etc.c.curl.CurlReadFunc.pause requestPause;
Value to return from onSend/onReceive delegates in order to pause a request

alias etc.c.curl.CurlReadFunc.abort requestAbort;
Value to return from onSend delegate in order to abort a request

@property bool isStopped();
True if the instance is stopped. A stopped instance is not usable.

void shutdown();
Stop and invalidate this instance.

@property void verbose(bool on);
Set verbose. This will print request information to stderr.

@property void dataTimeout(Duration d);
Set timeout for activity on connection.

@property void operationTimeout(Duration d);
Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc.

@property void connectTimeout(Duration d);
Set timeout for connecting.

@property void proxy(const(char)[] host);
Proxy

See:
proxy

@property void proxyPort(ushort port);
Proxy port

See:
proxy_port

alias etc.c.curl.CurlProxy CurlProxy;
Type of proxy

@property void proxyType(CurlProxy type);
Proxy type

See:
proxy_type

@property void dnsTimeout(Duration d);
DNS lookup timeout.

@property void netInterface(const(char)[] i);
@property void netInterface(const(ubyte)[4u] i);
@property void netInterface(InternetAddress i);
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:
std.socket.InternetAddress

@property void localPort(ushort port);
Set the local outgoing port to use.

Parameters:
ushort port the first outgoing port number to try and use

@property void localPortRange(ushort range);
Set the local outgoing port range to use. This can be used together with the localPort property.

Parameters:
ushort range if the first port is occupied then try this many port number forwards

@property void tcpNoDelay(bool on);
Set the tcp no-delay socket option on or off.

See:
nodelay

void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = "");
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.

Parameters:
const(char)[] username | the username
const(char)[] password | the password
const(char)[] domain | used for NTLM authentication only and is set to the NTLM domain name

@property void onSend(uint delegate(void[]) callback);
The event handler that gets called when data is needed for sending. The length of the 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 .abortRequest can be returned in order to abort the current request. The special value .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 onReceive(uint delegate(ubyte[]) 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 onProgress(int delegate(uint dlTotal, uint dlNow, uint ulTotal, uint ulNow) callback);
The event handler that gets called to inform of upload/download progress.

Parameters:
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();

void clearRequestHeaders();
Clear all outgoing headers.

void addRequestHeader(const(char)[] name, const(char)[] value);
Add a header e.g. "X-CustomField: Something is fishy".

There is no remove header functionality. Do a 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");
 string content = get("dlang.org", client);

@property string[string] responseHeaders();
The headers read from a successful response.

@property void method(Method m);
@property Method method();
HTTP method used.

@property StatusLine statusLine();
HTTP status line of last response. One call to perform may result in several requests because of redirection.

void setCookieJar(const(char)[] path);
Set a file path to where a cookie jar should be read/stored.

void flushCookieJar();
Flush cookie jar to disk.

void clearSessionCookies();
Clear session cookies.

void clearAllCookies();
Clear all cookies.

void setTimeCondition(HTTP.TimeCond cond, SysTime timestamp);
Set time condition on the request.

Parameters:
HTTP.TimeCond cond CurlTimeCond.{none,ifmodsince,ifunmodsince,lastmod}
SysTime timestamp Timestamp for the condition

RFC2616 Section 14.25

@property void postData(const(void)[] data);
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(char)[] data);
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 onReceiveHeader(void delegate(const(char[]) key, const(char[]) value) callback);
Set the event handler that receives incoming headers.

The callback will receive a header field key, value as parameter. The 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 onReceiveStatusLine(void delegate(StatusLine) callback);
Callback for each received StatusLine.

Notice that several callbacks can be done for each call to perform() due to redirections.

See Also:
StatusLine

@property void contentLength(size_t len);
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 size_t.max to reset to chunked transfer.

@property void authenticationMethod(AuthMethod authMethod);
Authentication method as specified in AuthMethod.

@property void maxRedirects(uint maxRedirs);
Set max allowed redirections using the location header. uint.max for infinite.

enum Method;
The standard HTTP methods : RFC2616 Section 5.1.1

head

get

post

put

del

options

trace

connect

struct StatusLine;
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.

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.

@safe void reset();
Reset this status line

string toString();

struct FTP;
FTP client functionality.

See Also:
RFC959

this(const(char)[] url);
FTP access to the specified url.

void perform();
Performs the ftp request as it has been configured.

After a FTP client has been setup and possibly assigned callbacks the perform() method will start performing the actual communication with the server.

@property void url(const(char)[] url);
The URL to specify the location of the resource.

alias etc.c.curl.CurlReadFunc.pause requestPause;
Value to return from onSend/onReceive delegates in order to pause a request

alias etc.c.curl.CurlReadFunc.abort requestAbort;
Value to return from onSend delegate in order to abort a request

@property bool isStopped();
True if the instance is stopped. A stopped instance is not usable.

void shutdown();
Stop and invalidate this instance.

@property void verbose(bool on);
Set verbose. This will print request information to stderr.

@property void dataTimeout(Duration d);
Set timeout for activity on connection.

@property void operationTimeout(Duration d);
Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc.

@property void connectTimeout(Duration d);
Set timeout for connecting.

@property void proxy(const(char)[] host);
Proxy

See:
proxy

@property void proxyPort(ushort port);
Proxy port

See:
proxy_port

alias etc.c.curl.CurlProxy CurlProxy;
Type of proxy

@property void proxyType(CurlProxy type);
Proxy type

See:
proxy_type

@property void dnsTimeout(Duration d);
DNS lookup timeout.

@property void netInterface(const(char)[] i);
@property void netInterface(const(ubyte)[4u] i);
@property void netInterface(InternetAddress i);
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:
std.socket.InternetAddress

@property void localPort(ushort port);
Set the local outgoing port to use.

Parameters:
ushort port the first outgoing port number to try and use

@property void localPortRange(ushort range);
Set the local outgoing port range to use. This can be used together with the localPort property.

Parameters:
ushort range if the first port is occupied then try this many port number forwards

@property void tcpNoDelay(bool on);
Set the tcp no-delay socket option on or off.

See:
nodelay

void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = "");
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.

Parameters:
const(char)[] username | the username
const(char)[] password | the password
const(char)[] domain | used for NTLM authentication only and is set to the NTLM domain name

@property void onSend(uint delegate(void[]) callback);
The event handler that gets called when data is needed for sending. The length of the 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 .abortRequest can be returned in order to abort the current request. The special value .pauseRequest can be returned in order to pause the current request.

@property void onReceive(uint delegate(ubyte[]) 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 onProgress(int delegate(uint dlTotal, uint dlNow, uint ulTotal, uint ulNow) callback);
The event handler that gets called to inform of upload/download progress.

Parameters:
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

void clearCommands();
Clear all commands send to ftp server.

void addCommand(const(char)[] command);
Add a command to send to ftp server.

There is no remove command functionality. Do a 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);

@property void contentLength(size_t len);
The content length in bytes of the ftp data.

struct SMTP;
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 = ["<to.addr@gmail.com>"];
 smtp.mailFrom = "<from.addr@gmail.com>";
 smtp.message = "Example Message";
 smtp.perform();

See Also:
RFC2821

this(string url);
Sets to the URL of the SMTP server.

void perform();
Performs the request as configured.

@property void url(const(char)[] url);
The URL to specify the location of the resource.

alias etc.c.curl.CurlReadFunc.pause requestPause;
Value to return from onSend/onReceive delegates in order to pause a request

alias etc.c.curl.CurlReadFunc.abort requestAbort;
Value to return from onSend delegate in order to abort a request

@property bool isStopped();
True if the instance is stopped. A stopped instance is not usable.

void shutdown();
Stop and invalidate this instance.

@property void verbose(bool on);
Set verbose. This will print request information to stderr.

@property void dataTimeout(Duration d);
Set timeout for activity on connection.

@property void operationTimeout(Duration d);
Set maximum time an operation is allowed to take. This includes dns resolution, connecting, data transfer, etc.

@property void connectTimeout(Duration d);
Set timeout for connecting.

@property void proxy(const(char)[] host);
Proxy

See:
proxy

@property void proxyPort(ushort port);
Proxy port

See:
proxy_port

alias etc.c.curl.CurlProxy CurlProxy;
Type of proxy

@property void proxyType(CurlProxy type);
Proxy type

See:
proxy_type

@property void dnsTimeout(Duration d);
DNS lookup timeout.

@property void netInterface(const(char)[] i);
@property void netInterface(const(ubyte)[4u] i);
@property void netInterface(InternetAddress i);
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:
std.socket.InternetAddress

@property void localPort(ushort port);
Set the local outgoing port to use.

Parameters:
ushort port the first outgoing port number to try and use

@property void localPortRange(ushort range);
Set the local outgoing port range to use. This can be used together with the localPort property.

Parameters:
ushort range if the first port is occupied then try this many port number forwards

@property void tcpNoDelay(bool on);
Set the tcp no-delay socket option on or off.

See:
nodelay

void setAuthentication(const(char)[] username, const(char)[] password, const(char)[] domain = "");
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.

Parameters:
const(char)[] username | the username
const(char)[] password | the password
const(char)[] domain | used for NTLM authentication only and is set to the NTLM domain name

@property void onSend(uint delegate(void[]) callback);
The event handler that gets called when data is needed for sending. The length of the 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 .abortRequest can be returned in order to abort the current request. The special value .pauseRequest can be returned in order to pause the current request.

@property void onReceive(uint delegate(ubyte[]) 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 onProgress(int delegate(uint dlTotal, uint dlNow, uint ulTotal, uint ulNow) callback);
The event handler that gets called to inform of upload/download progress.

Parameters:
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

void mailFrom()(const(char)[] sender);
Setter for the sender's email address.

void mailTo()(const(char)[][] recipients...);
Setter for the recipient email addresses.

@property void message(string msg);
Sets the message body text.

class CurlException: object.Exception;
Exception thrown on errors in std.net.curl functions.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);
Parameters:
string msg | The message for the exception.
string file | The file where the exception occurred.
size_t line | The line number where the exception occurred.
Throwable next | The previous exception in the chain of exceptions, if any.

class CurlTimeoutException: std.net.curl.CurlException;
Exception thrown on timeout errors in std.net.curl functions.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);
Parameters:
string msg | The message for the exception.
string file | The file where the exception occurred.
size_t line | The line number where the exception occurred.
Throwable next | The previous exception in the chain of exceptions, if any.

alias int CurlCode;
Equal to etc.c.curl.CURLcode

struct Curl;
Wrapper to provide a better interface to libcurl than using the plain C API. It is recommended to use the HTTP/FTP etc. structs instead unless raw access to libcurl is needed.

void initialize();
Initialize the instance by creating a working curl handle.

Curl dup();
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.

void shutdown();
Stop and invalidate this curl instance.

Warning:
Do not call this from inside a callback handler e.g. onReceive.

void pause(bool sendingPaused, bool receivingPaused);
Pausing and continuing transfers.

void set(CurlOption option, const(char)[] value);
Set a string curl option.

Parameters:
CurlOption option | A etc.c.curl.CurlOption as found in the curl documentation
const(char)[] value | The string

void set(CurlOption option, long value);
Set a long curl option.

Parameters:
CurlOption option | A etc.c.curl.CurlOption as found in the curl documentation
long value | The long

void set(CurlOption option, void* value);
Set a void* curl option.

Parameters:
CurlOption option | A etc.c.curl.CurlOption as found in the curl documentation
void* value | The pointer

void clear(CurlOption option);
Clear a pointer option.

Parameters:
CurlOption option A etc.c.curl.CurlOption as found in the curl documentation

CurlCode perform(bool throwOnError = true);
perform the curl request by doing the HTTP,FTP etc. as it has been setup beforehand.

@property void onReceive(uint delegate(ubyte[]) callback);
The event handler that receives incoming data.

Parameters:
uint delegate(ubyte[]) callback the callback that receives the 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 onReceiveHeader(void delegate(const(char[])) callback);
The event handler that receives incoming headers for protocols that uses headers.

Parameters:
void delegate(const(char[])) 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 onSend(uint delegate(void[]) callback);
The event handler that gets called when data is needed for sending.

Parameters:
uint delegate(void[]) callback the callback that has a 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 Curl.abortRequest can be returned in order to abort the current request. The special value 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 onSeek(CurlSeek delegate(long, CurlSeekPos) callback);
The event handler that gets called when the curl backend needs to seek the data to be sent.

Parameters:
CurlSeek delegate(long, CurlSeekPos) callback the callback that receives a seek offset and a seek position etc.c.curl.CurlSeekPos

Returns:
The callback returns the success state of the seeking etc.c.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 onSocketOption(int delegate(socket_t, CurlSockType) callback);
The event handler that gets called when the net socket has been created but a connect() call has not yet been done. This makes it possible to set misc. socket options.

Parameters:
int delegate(socket_t, CurlSockType) callback the callback that receives the socket and socket type etc.c.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 onProgress(int delegate(uint dlTotal, uint dlNow, uint ulTotal, uint ulNow) callback);
The event handler that gets called to inform of upload/download progress.

Parameters:
int delegate(uint dlTotal, uint dlNow, uint ulTotal, uint ulNow) 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();
 };

Copyright Jonas Drewsen 2011-2012 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.net.isemail

Validates an email address according to RFCs 5321, 5322 and others.

Authors:
Dominic Sayers , Jacob Carlborg

License:
Boost Software License 1.0

Version:
3.0.13 - Version 3.0 of the original PHP implementation: http://www.dominicsayers.com/isemail

Standards:
  • RFC 5321
  • RFC 5322

References:
  • http://www.dominicsayers.com/isemail
  • http://tools.ietf.org/html/rfc5321
  • http://tools.ietf.org/html/rfc5322

Source:
std/net/isemail.d

EmailStatus isEmail(Char)(const(Char)[] email, CheckDns checkDNS = CheckDns.no, EmailStatusCode errorLevel = EmailStatusCode.none);
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.

Parameters:
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 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.

enum CheckDns;
Enum for indicating if the isEmail function should perform a DNS check or not.

no
Does not perform DNS checking

yes
Performs DNS checking

struct EmailStatus;
This struct represents the status of an email address

@property bool valid();
Indicates if the email address is valid or not.

@property string localPart();
The local part of the email address, that is, the part before the @ sign.

@property string domainPart();
The domain part of the email address, that is, the part after the @ sign.

@property EmailStatusCode statusCode();
The email status code

@property string status();
Returns a describing string of the status code

string toString();
Returns a textual representation of the email status

string statusCodeDescription(EmailStatusCode statusCode);
Returns a describing string of the given status code

enum EmailStatusCode;
An email status code, indicating if an email address is valid or not. If it is invalid it also indicates why.

validCategory
Address is valid

dnsWarning
Address is valid but a DNS check was not successful

rfc5321
Address is valid for SMTP but has unusual elements

cFoldingWhitespace
Address is valid within the message but cannot be used unmodified for the envelope

deprecated_
Address contains deprecated elements but may still be valid in restricted contexts

rfc5322
The address is only valid according to the broad definition of RFC 5322. It is otherwise invalid

any
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.

none
Address is either considered valid or not, no finer grained error checking is performed. Returned email status code will be either Error or Valid.

warning
Address containing warnings is considered valid, that is, any status code below 16 is considered valid.

error
Address is invalid for any purpose

valid
Address is valid

dnsWarningNoMXRecord
Could not find an MX record for this domain but an A-record does exist

dnsWarningNoRecord
Could not find an MX record or an A-record for this domain

rfc5321TopLevelDomain
Address is valid but at a Top Level Domain

rfc5321TopLevelDomainNumeric
Address is valid but the Top Level Domain begins with a number

rfc5321QuotedString
Address is valid but contains a quoted string

rfc5321AddressLiteral
Address is valid but at a literal address not a domain

rfc5321IpV6Deprecated
Address is valid but contains a :: that only elides one zero group

comment
Address contains comments

foldingWhitespace
Address contains Folding White Space

deprecatedLocalPart
The local part is in a deprecated form

deprecatedFoldingWhitespace
Address contains an obsolete form of Folding White Space

deprecatedQuotedText
A quoted string contains a deprecated character

deprecatedQuotedPair
A quoted pair contains a deprecated character

deprecatedComment
Address contains a comment in a position that is deprecated

deprecatedCommentText
A comment contains a deprecated character

deprecatedCommentFoldingWhitespaceNearAt
Address contains a comment or Folding White Space around the @ sign

rfc5322Domain
Address is RFC 5322 compliant but contains domain characters that are not allowed by DNS

rfc5322TooLong
Address is too long

rfc5322LocalTooLong
The local part of the address is too long

rfc5322DomainTooLong
The domain part is too long

rfc5322LabelTooLong
The domain part contains an element that is too long

rfc5322DomainLiteral
The domain literal is not a valid RFC 5321 address literal

rfc5322DomainLiteralObsoleteText
The domain literal is not a valid RFC 5321 address literal and it contains obsolete characters

rfc5322IpV6GroupCount
The IPv6 literal address contains the wrong number of groups

rfc5322IpV6TooManyDoubleColons
The IPv6 literal address contains too many :: sequences

rfc5322IpV6BadChar
The IPv6 address contains an illegal group of characters

rfc5322IpV6MaxGroups
The IPv6 address has too many groups

rfc5322IpV6ColonStart
IPv6 address starts with a single colon

rfc5322IpV6ColonEnd
IPv6 address ends with a single colon

errorExpectingDomainText
A domain literal contains a character that is not allowed

errorNoLocalPart
Address has no local part

errorNoDomain
Address has no domain part

errorConsecutiveDots
The address may not contain consecutive dots

errorTextAfterCommentFoldingWhitespace
Address contains text after a comment or Folding White Space

errorTextAfterQuotedString
Address contains text after a quoted string

errorTextAfterDomainLiteral
Extra characters were found after the end of the domain literal

errorExpectingQuotedPair
The address contains a character that is not allowed in a quoted pair

errorExpectingText
Address contains a character that is not allowed

errorExpectingQuotedText
A quoted string contains a character that is not allowed

errorExpectingCommentText
A comment contains a character that is not allowed

errorBackslashEnd
The address cannot end with a backslash

errorDotStart
Neither part of the address may begin with a dot

errorDotEnd
Neither part of the address may end with a dot

errorDomainHyphenStart
A domain or subdomain cannot begin with a hyphen

errorDomainHyphenEnd
A domain or subdomain cannot end with a hyphen

errorUnclosedQuotedString
Unclosed quoted string

errorUnclosedComment
Unclosed comment

errorUnclosedDomainLiteral
Domain literal is missing its closing bracket

errorFoldingWhitespaceCrflX2
Folding White Space contains consecutive CRLF sequences

errorFoldingWhitespaceCrLfEnd
Folding White Space ends with a CRLF sequence

errorCrNoLf
Address contains a carriage return that is not followed by a line feed

Dominic Sayers, Jacob Carlborg 2008-. Test schema documentation: Copyright © 2011, Daniel Marschall | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.digest.crc

Category | Functions
Template API | CRC32
OOP API | CRC32Digest
Helpers | crcHexString crc32Of

Cyclic Redundancy Check (32-bit) implementation.

This module conforms to the APIs defined in std.digest.digest. To understand the differences between the template and the OOP API, see std.digest.digest.

This module publicly imports std.digest.digest and can be used as a stand-alone module.

Note:
CRCs are usually printed with the MSB first. When using std.digest.digest.toHexString the result will be in an unexpected order. Use std.digest.digest.toHexStrings optional order parameter to specify decreasing order for the correct result. The crcHexString alias can also be used for this purpose.

License:
Boost License 1.0

Authors:
Pavel "EvilOne" Minayev, Alex Rønne Petersen, Johannes Pfau

References:
Wikipedia on CRC

Source:
std/digest/crc.d

Standards:
Implements the 'common' IEEE CRC32 variant (LSB-first order, Initial value uint.max, complement result)

CTFE:
Digests do not work in CTFE

Examples:
 //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();

 //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");

 //Feeding data
 ubyte[1024] data;
 crc.put(data[]);
 crc.reset(); //Start again
 crc.put(data[]);
 hash = crc.finish();

struct CRC32;
Template API CRC32 implementation. See std.digest.digest for differences between template and OOP API.

Examples:
 //Simple example, hashing a string using crc32Of helper function
 ubyte[4] hash = crc32Of("abc");
 //Let's get a hash string
 assert(crcHexString(hash) == "352441C2");

 //Using the basic API
 CRC32 hash;
 ubyte[1024] data;
 //Initialize data here...
 hash.put(data);
 ubyte[4] result = hash.finish();

 //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");

pure nothrow @trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 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

pure nothrow @trusted void start();
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.

Examples:
 CRC32 digest;
 //digest.start(); //Not necessary
 digest.put(0);

pure nothrow @trusted ubyte[4u] finish();
Returns the finished CRC32 hash. This also calls start to reset the internal state.

Examples:
 //Simple example
 CRC32 hash;
 hash.put(cast(ubyte)0);
 ubyte[4] result = hash.finish();

const pure nothrow @trusted ubyte[4u] peek();
Works like finish but does not reset the internal state, so it's possible to continue putting data into this CRC32 after a call to peek.

auto crc32Of(T...)(T data);
This is a convenience alias for std.digest.digest.digest using the CRC32 implementation.

Examples:
 ubyte[4] hash = crc32Of("abc");
 assert(hash == digest!CRC32("abc")); //This is the same as above

alias toHexString crcHexString;
alias std.digest.digest.toHexString!(cast(Order)true, 16).toHexString crcHexString;
This is a convenience alias for std.digest.digest.toHexString producing the usual CRC32 string output.

alias std.digest.digest.WrapperDigest!(CRC32).WrapperDigest CRC32Digest;
OOP API CRC32 implementation. See std.digest.digest for differences between template and OOP API.

This is an alias for std.digest.digest.WrapperDigest!CRC32, see std.digest.digest.WrapperDigest for more information.

Examples:
 //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");

 //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");

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.digest.digest

Category | Functions
Template API | isDigest DigestType hasPeek ExampleDigest digest hexDigest makeDigest
OOP API | Digest
Helper functions | toHexString
Implementation helpers | digestLength WrapperDigest

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.

APIs:
There are two APIs for digests: The template API and the OOP API. The template API uses structs and template helpers like isDigest. The OOP API implements digests as classes inheriting the Digest interface. All digests are named so that the template API struct is called "x" and the OOP API class is called "xDigest". For example we have MD5 <--> MD5Digest, CRC32 <--> 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 Digest classes still have to be created using 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 "x" structs directly.

License:
Boost License 1.0

Authors:
Johannes Pfau

Source:
std/digest/digest.d

CTFE:
Digests do not work in CTFE

Examples:
 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");

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

 //Generating the hashes of a file using the template API, old school way
 import std.digest.crc, std.digest.sha, std.digest.md;
 import std.stdio;

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

 // Digests a file and prints the result.
 void digestFile(Hash)(ref Hash hash, string filename) if(isDigest!Hash)
 {
     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);

     auto result = hash.finish();
     writefln("%s (%s) = %s", hash.stringof, filename, toHexString(result));
 }

 //The same using the OOP API
 import std.digest.crc, std.digest.sha, std.digest.md;
 import std.stdio;

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

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

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)

struct 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 isDigest test.

Note:
  • A digest must be a struct (value type) to pass the isDigest test.
  • A digest passing the isDigest test is always an OutputRange

Examples:
 //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");

@trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[]. The following usages of put must work for any type which passes isDigest:

Examples:
 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 start();
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 ubyte[16u] finish();
The finish function returns the final hash sum and resets the Digest.

Note:
The actual type returned by finish depends on the digest implementation. ubyte[16] is just used as an example. It is guaranteed that the type is a static array of ubytes.

  • Use DigestType to obtain the actual return type.
  • Use digestLength to obtain the length of the ubyte array.

template isDigest(T)
Use this to check if a type is a digest. See ExampleDigest to see what a type must provide to pass this check.

Note:
This is very useful as a template constraint (see examples)

Examples:
 import std.digest.crc;
 static assert(isDigest!CRC32);

 void myFunction(T)() if(isDigest!T)
 {
     T dig;
     dig.start();
     auto result = dig.finish();
 }

BUGS:
  • Does not yet verify that put takes scope parameters.
  • Should check that finish() returns a ubyte[num] array

template DigestType(T)
Use this template to get the type which is returned by a digest's finish method.

Examples:
 import std.digest.crc;
 assert(is(DigestType!(CRC32) == ubyte[4]));

 import std.digest.crc;
 CRC32 dig;
 dig.start();
 DigestType!CRC32 result = dig.finish();

template hasPeek(T)
Used to check if a digest supports the peek method. Peek has exactly the same function signatures as finish, but it doesn't reset the digest's internal state.

Note:
  • This is very useful as a template constraint (see examples)
  • This also checks if T passes isDigest

Examples:
 import std.digest.crc, std.digest.md;
 assert(!hasPeek!(MD5));
 assert(hasPeek!CRC32);

 void myFunction(T)() if(hasPeek!T)
 {
     T dig;
     dig.start();
     auto result = dig.peek();
 }

DigestType!(Hash) digest(Hash, Range)(auto ref Range range);
This is a convenience function to calculate a hash using the template API. Every digest passing the isDigest test can be used with this function.

Parameters:
range an InputRange with ElementType ubyte, ubyte[] or ubyte[num]

Examples:
 import std.digest.md;
 auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
 auto md5 = digest!MD5(testRange);

DigestType!(Hash) digest(Hash, T...)(scope const T data);
This overload of the digest function handles arrays.

Parameters:
data one or more arrays of any type

Examples:
 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");

 //It's also possible to pass multiple values to this function:
 import std.digest.crc;
 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(toHexString(crc32) == "39A34F41");

char[digestLength!(Hash) * 2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range);
This is a convenience function similar to digest, but it returns the string representation of the hash. Every digest passing the isDigest test can be used with this function.

Parameters:
Order | the order in which the bytes are processed (see toHexString)
range | an InputRange with ElementType ubyte, ubyte[] or ubyte[num]

Examples:
 import std.digest.md;
 auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
 assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF");

char[digestLength!(Hash) * 2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data);
This overload of the hexDigest function handles arrays.

Parameters:
Order | the order in which the bytes are processed (see toHexString)
data | one or more arrays of any type

Examples:
 import std.digest.crc;
 assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339");

 //It's also possible to pass multiple values to this function:
 import std.digest.crc;
 assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339");

Hash makeDigest(Hash)();
This is a convenience function which returns an initialized digest, so it's not necessary to call start manually.

Examples:
 import std.digest.md;
 auto md5 = makeDigest!MD5();
 md5.put("Hello");
 assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71");

abstract interface Digest;
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 OutputRange

Examples:
 //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");

abstract nothrow @trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 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
 }

abstract nothrow @trusted void reset();
Resets the internal state of the digest.

Note:
finish calls this internally, so it's not necessary to call reset manually after a call to finish.

abstract const nothrow @property @trusted size_t length();
This is the length in bytes of the hash value which is returned by finish. It's also the required size of a buffer passed to finish.

abstract nothrow @trusted ubyte[] finish();
abstract nothrow ubyte[] finish(scope ubyte[] buf);
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 length bytes big.

final nothrow @trusted ubyte[] digest(scope const(void[])[] data...);
This is a convenience function to calculate the hash of a value using the OOP API.

Examples:
 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");

 //It's also possible to pass multiple values to this function:
 import std.digest.crc;
 ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(crcHexString(crc32) == "414FA339");

enum Order;
See toHexString

increasing

decreasing

char[num * 2] toHexString(Order order = Order.increasing, size_t num)(in ubyte[num] digest);
string toHexString(Order order = Order.increasing)(in ubyte[] digest);
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.

Examples:
 //With template API:
 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(toHexString(crc32) == "39A34F41");

 //Usually CRCs are printed in this order, though:
 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(toHexString!(Order.decreasing)(crc32) == "414FA339");

 //With OOP API:
 auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(toHexString(crc32) == "39A34F41");

 //Usually CRCs are printed in this order, though:
 auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(toHexString!(Order.decreasing)(crc32) == "414FA339");

template digestLength(T) if (isDigest!(T))
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.

class WrapperDigest(T) if (isDigest!(T)): Digest;
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, ...).

this();
Initializes the digest.

void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 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
 }

void reset();
Resets the internal state of the digest.

Note:
finish calls this internally, so it's not necessary to call reset manually after a call to finish.

const pure size_t length();
This is the length in bytes of the hash value which is returned by finish. It's also the required size of a buffer passed to finish.

ubyte[] finish(scope ubyte[] buf);
ubyte[] finish();
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 length bytes.

Examples:
 //Simple example
 import std.digest.md;
 auto hash = new WrapperDigest!MD5();
 hash.put(cast(ubyte)0);
 auto result = hash.finish();

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

const ubyte[] peek(scope ubyte[] buf);
const ubyte[] peek();
Works like 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 hasPeek!T is true.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.digest.md

Category | Functions
Template API | MD5
OOP API | MD5Digest
Helpers | md5Of

Computes MD5 hashes of arbitrary data. MD5 hashes are 16 byte quantities that are like a checksum or CRC, but are more robust.

This module conforms to the APIs defined in std.digest.digest. To understand the differences between the template and the OOP API, see std.digest.digest.

This module publicly imports std.digest.digest and can be used as a stand-alone module.

License:
Boost License 1.0

CTFE:
Digests do not work in CTFE

Authors:
Piotr Szturmaj, Kai Nacke, Johannes Pfau
The routines and algorithms are derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.

References:
Wikipedia on MD5

Source:
std/digest/md.d

Examples:
 //Template API
 import std.digest.md;

 ubyte[16] hash = md5Of("abc");
 assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72");

 //Feeding data
 ubyte[1024] data;
 MD5 md5;
 md5.start();
 md5.put(data[]);
 md5.start(); //Start again
 md5.put(data[]);
 hash = md5.finish();

 //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();

struct MD5;
Template API MD5 implementation. See std.digest.digest for differences between template and OOP API.

Examples:
 //Simple example, hashing a string using md5Of helper function
 ubyte[16] hash = md5Of("abc");
 //Let's get a hash string
 assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72");

 //Using the basic API
 MD5 hash;
 hash.start();
 ubyte[1024] data;
 //Initialize data here...
 hash.put(data);
 ubyte[16] result = hash.finish();

 //Let's use the template features:
 //Note: When passing a MD5 to a function, it must be passed by referece!
 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");

pure nothrow @trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 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

pure nothrow @trusted void start();
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.

Examples:
 MD5 digest;
 //digest.start(); //Not necessary
 digest.put(0);

pure nothrow @trusted ubyte[16u] finish();
Returns the finished MD5 hash. This also calls start to reset the internal state.

Examples:
 //Simple example
 MD5 hash;
 hash.start();
 hash.put(cast(ubyte)0);
 ubyte[16] result = hash.finish();

auto md5Of(T...)(T data);
This is a convenience alias for std.digest.digest.digest using the MD5 implementation.

Examples:
 ubyte[16] hash = md5Of("abc");
 assert(hash == digest!MD5("abc")); //This is the same as above

alias std.digest.digest.WrapperDigest!(MD5).WrapperDigest MD5Digest;
OOP API MD5 implementation. See std.digest.digest for differences between template and OOP API.

This is an alias for std.digest.digest.WrapperDigest!MD5, see std.digest.digest.WrapperDigest for more information.

Examples:
 //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");

 //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");

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.digest.ripemd

Category | Functions
Template API | RIPEMD160
OOP API | RIPEMD160Digest
Helpers | ripemd160Of

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.

This module conforms to the APIs defined in std.digest.digest. To understand the differences between the template and the OOP API, see std.digest.digest.

This module publicly imports std.digest.digest and can be used as a stand-alone module.

License:
Boost License 1.0

CTFE:
Digests do not work in CTFE

Authors:
Kai Nacke
The algorithm was designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel.
The D implementation is a direct translation of the ANSI C implementation by Antoon Bosselaers.

References:
The hash function RIPEMD-160 Wikipedia on RIPEMD-160

Source:
std/digest/md.d

Examples:
 //Template API
 import std.digest.ripemd;

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

 //OOP API
 import std.digest.ripemd;

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

struct RIPEMD160;
Template API RIPEMD160 implementation. See std.digest.digest for differences between template and OOP API.

Examples:
 //Simple example, hashing a string using ripemd160Of helper function
 ubyte[20] hash = ripemd160Of("abc");
 //Let's get a hash string
 assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC");

 //Using the basic API
 RIPEMD160 hash;
 hash.start();
 ubyte[1024] data;
 //Initialize data here...
 hash.put(data);
 ubyte[20] result = hash.finish();

 //Let's use the template features:
 //Note: When passing a RIPEMD160 to a function, it must be passed by referece!
 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");

pure nothrow @trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 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

pure nothrow @trusted void start();
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.

Examples:
 RIPEMD160 digest;
 //digest.start(); //Not necessary
 digest.put(0);

pure nothrow @trusted ubyte[20u] finish();
Returns the finished RIPEMD160 hash. This also calls start to reset the internal state.

Examples:
 //Simple example
 RIPEMD160 hash;
 hash.start();
 hash.put(cast(ubyte)0);
 ubyte[20] result = hash.finish();
 assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D");

auto ripemd160Of(T...)(T data);
This is a convenience alias for std.digest.digest.digest using the RIPEMD160 implementation.

Examples:
 ubyte[20] hash = ripemd160Of("abc");
 assert(hash == digest!RIPEMD160("abc")); //This is the same as above

alias std.digest.digest.WrapperDigest!(RIPEMD160).WrapperDigest RIPEMD160Digest;
OOP API RIPEMD160 implementation. See std.digest.digest for differences between template and OOP API.

This is an alias for std.digest.digest.WrapperDigest!RIPEMD160, see std.digest.digest.WrapperDigest for more information.

Examples:
 //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");

 //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");

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.digest.sha

Category | Functions
Template API | SHA1
OOP API | SHA1Digest
Helpers | sha1Of

Computes SHA1 hashes of arbitrary data. SHA1 hashes are 20 byte quantities that are like a checksum or CRC, but are more robust.

This module conforms to the APIs defined in std.digest.digest. To understand the differences between the template and the OOP API, see std.digest.digest.

This module publicly imports std.digest.digest and can be used as a stand-alone module.

License:
Boost License 1.0

CTFE:
Digests do not work in CTFE

Authors:
The routines and algorithms are derived from the Secure Hash Signature Standard (SHS) (FIPS PUB 180-2).
Kai Nacke, Johannes Pfau

References:
  • FIPS PUB180-2
  • Fast implementation of SHA1
  • Wikipedia article about SHA

Source:
std/digest/sha.d

Examples:
 //Template API
 import std.digest.sha;

 ubyte[20] hash = sha1Of("abc");
 assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D");

 //Feeding data
 ubyte[1024] data;
 SHA1 sha;
 sha.start();
 sha.put(data[]);
 sha.start(); //Start again
 sha.put(data[]);
 hash = sha.finish();

 //OOP API
 import std.digest.sha;

 auto sha = new SHA1Digest();
 ubyte[] hash = sha.digest("abc");
 assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D");

 //Feeding data
 ubyte[1024] data;
 sha.put(data[]);
 sha.reset(); //Start again
 sha.put(data[]);
 hash = sha.finish();

struct SHA1;
Template API SHA1 implementation. See std.digest.digest for differences between template and OOP API.

Examples:
 //Simple example, hashing a string using sha1Of helper function
 ubyte[20] hash = sha1Of("abc");
 //Let's get a hash string
 assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D");

 //Using the basic API
 SHA1 hash;
 hash.start();
 ubyte[1024] data;
 //Initialize data here...
 hash.put(data);
 ubyte[20] result = hash.finish();

 //Let's use the template features:
 //Note: When passing a SHA1 to a function, it must be passed by referece!
 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");

pure nothrow @trusted void start();
SHA1 initialization. Begins a SHA1 operation.

Note:
For this SHA1 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.

Examples:
 SHA1 digest;
 //digest.start(); //Not necessary
 digest.put(0);

pure nothrow @trusted void put(scope const(ubyte)[] input...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 SHA1 dig;
 dig.put(cast(ubyte)0); //single ubyte
 dig.put(cast(ubyte)0, cast(ubyte)0); //variadic
 ubyte[10] buf;
 dig.put(buf); //buffer

pure nothrow @trusted ubyte[20u] finish();
Returns the finished SHA1 hash. This also calls start to reset the internal state.

Examples:
 //Simple example
 SHA1 hash;
 hash.start();
 hash.put(cast(ubyte)0);
 ubyte[20] result = hash.finish();

auto sha1Of(T...)(T data);
This is a convenience alias for std.digest.digest.digest using the SHA1 implementation.

Examples:
 ubyte[20] hash = sha1Of("abc");
 assert(hash == digest!SHA1("abc")); //This is the same as above

alias std.digest.digest.WrapperDigest!(SHA1).WrapperDigest SHA1Digest;
OOP API SHA1 implementation. See std.digest.digest for differences between template and OOP API.

This is an alias for std.digest.digest.WrapperDigest!SHA1, see std.digest.digest.WrapperDigest for more information.

Examples:
 //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");

 //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");

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.windows.charset

Support UTF-8 on Windows 95, 98 and ME systems.

License:
Boost License 1.0.

Authors:
Walter Bright

const(char)* toMBSz(in char[] s, uint codePage = 0);
Converts the UTF-8 string s into a null-terminated string in a Windows 8-bit character set.

Parameters:
char[] s | UTF-8 string to convert.
uint codePage | is the number of the target codepage, or 0 - ANSI, 1 - OEM, 2 - Mac

Authors:
yaneurao, Walter Bright, Stewart Gordon

string fromMBSz(immutable(char)* s, int codePage = 0);
Converts the null-terminated string s from a Windows 8-bit character set into a UTF-8 char array.

Parameters:
immutable(char)* s | UTF-8 string to convert.
int codePage | is the number of the source codepage, or 0 - ANSI, 1 - OEM, 2 - Mac

Authors:
Stewart Gordon, Walter Bright

Copyright Digital Mars 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

etc.c.curl

This is an interface to the libcurl library.

Converted to D from curl headers by htod and cleaned up by Jonas Drewsen (jdrewsen)

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

string LIBCURL_COPYRIGHT;
This is the global package copyright

string LIBCURL_VERSION;
This is the version number of the libcurl package from which this header file origins:

int LIBCURL_VERSION_MAJOR;
int LIBCURL_VERSION_MINOR;
int LIBCURL_VERSION_PATCH;
The numeric version number is also available "in parts" by using these constants

int LIBCURL_VERSION_NUM;
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.

string LIBCURL_TIMESTAMP;
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"

alias long curl_off_t;
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 void CURL;

alias std.socket.socket_t curl_socket_t;
jdrewsen - Get socket alias from std.socket

const const(int) CURL_SOCKET_BAD;
jdrewsen - Would like to get socket error constant from std.socket by it is private atm.

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

int HTTPPOST_FILENAME;
specified content is a file name

int HTTPPOST_READFILE;
specified content is a file name

int HTTPPOST_PTRNAME;
name is only stored pointer do not free in formfree

int HTTPPOST_PTRCONTENTS;
contents is only stored pointer do not free in formfree

int HTTPPOST_BUFFER;
upload file from buffer

int HTTPPOST_PTRBUFFER;
upload file from pointer contents

int HTTPPOST_CALLBACK;
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;

int CURL_MAX_WRITE_SIZE;
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).

int CURL_MAX_HTTP_HEADER;
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

int CURL_WRITEFUNC_PAUSE;
This is a magic return code for the write callback that, when returned, will signal libcurl to pause receiving on the current transfer.

alias uint function(char* buffer, uint size, uint nitems, void* outstream) curl_write_callback;

enum CurlFileType;
enumeration of file types

file

directory

symlink

device_block

device_char

namedpipe

socket

door

unknown
is possible only on Sun Solaris now

alias int curlfiletype;

enum CurlFInfoFlagKnown;

filename

filetype

time

perm

uid

gid

size

hlinkcount

struct _N2;
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.

char* time;

char* perm;

char* user;

char* group;

char* target;
pointer to the target filename of a symlink

struct curl_fileinfo;
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.

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;

enum CurlChunkBgnFunc;
return codes for CURLOPT_CHUNK_BGN_FUNCTION

ok

fail
tell the lib to end the task

skip
skip this chunk over

alias int function(void* transfer_info, void* ptr, int remains) curl_chunk_bgn_callback;
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

enum CurlChunkEndFunc;
return codes for CURLOPT_CHUNK_END_FUNCTION

ok

fail

alias int function(void* ptr) curl_chunk_end_callback;
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.

enum CurlFnMAtchFunc;
return codes for FNMATCHFUNCTION

match

nomatch

fail

alias int function(void* ptr, char* pattern, char* string) curl_fnmatch_callback;
callback type for wildcard downloading pattern matching. If the string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc.

enum CurlSeekPos;
seek whence...

set

current

end

enum CurlSeek;
These are the return codes for the seek callbacks

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, long offset, int origin) curl_seek_callback;

enum CurlReadFunc;

abort
This is a return code for the read callback that, when returned, will signal libcurl to immediately abort the current transfer.

pause
This is a return code for the read callback that, when returned, will const signal libcurl to pause sending data on the current transfer.

alias uint function(char* buffer, uint size, uint nitems, void* outstream) curl_read_callback;

enum CurlSockType;

ipcxn
socket created for a specific IP connection

last
never use

alias int curlsocktype;

alias int function(void* clientp, socket_t curlfd, int purpose) curl_sockopt_callback;

struct curl_sockaddr;
addrlen was a socklen_t type before 7.18.0 but it turned really ugly and painful on the systems that lack this type

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 socket_t function(void* clientp, int 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 int function(void* handle, int cmd, void* clientp) curl_ioctl_callback;

alias void* function(uint size) curl_malloc_callback;
alias void function(void*) curl_free_callback;
alias void* function(void* ptr, uint size) curl_realloc_callback;
alias char* function(char* str) curl_strdup_callback;
alias void* function(uint nmemb, uint size) curl_calloc_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.

enum CurlCallbackInfo;
the kind of data that is passed to information_callback

text

header_in

header_out

data_in

data_out

ssl_data_in

ssl_data_out

end

alias int curl_infotype;

alias int function(void* handle, int type, char* data, uint size, void* userptr) curl_debug_callback;

enum CurlError;
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!

ok

unsupported_protocol
1

failed_init
2

url_malformat
3

obsolete4
4 - NOT USED

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

operation_timedout
Note:
CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error instead of a memory allocation error if CURL_DOES_CONVERSIONS is defined 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_telnet_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;

alias int function(char* buffer, uint length) curl_conv_callback;
This prototype applies to all conversion callbacks

alias int function(void* curl, void* ssl_ctx, void* userptr) curl_ssl_ctx_callback;
actually an OpenSSL SSL_CTX

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
support added in 7.15.2, enum existed already in 7.10

socks5
added in 7.10

socks4a
added in 7.18.0

socks5_hostname
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;

basic
Basic (default)

digest
Digest

gssnegotiate
GSS-Negotiate

ntlm
NTLM

digest_ie
Digest with IE flavour

only
used together with a single other type to force no auth or just that single type

any
all fine types set

anysafe

enum CurlSshAuth;

any
all types supported by the server

none
none allowed, silly but complete

publickey
public/private key files

password
password

host
host key files

keyboard
keyboard interactive

int CURL_ERROR_SIZE;

enum CurlKHType;
points to a zero-terminated string encoded with base64 if len is zero, otherwise to the "raw" data

unknown

rsa1

rsa

dss

struct curl_khkey;

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;

enum CurlKHStat;
this is the set of return values expected from the curl_sshkeycallback callback

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

enum CurlKHMatch;
this is the set of status codes pass in to the callback

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(void* easy, curl_khkey* knownkey, curl_khkey* foundkey, CurlKHMatch m, void* clientp) curl_sshkeycallback;

enum CurlUseSSL;
parameter for the CURLOPT_USE_SSL option

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;

enum CurlFtpSSL;
parameter for the CURLOPT_FTP_SSL_CCC option

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;

enum CurlFtpAuth;
parameter for the CURLOPT_FTPSSLAUTH option

defaultauth
let libcurl decide

ssl
use "AUTH SSL"

tls
use "AUTH TLS"

last
not an option, never use

alias int curl_ftpauth;

enum CurlFtp;
parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option

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;

enum CurlFtpMethod;
parameter for the CURLOPT_FTP_FILEMETHOD option

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;

enum CurlProto;
CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options

http

https

ftp

ftps

scp

sftp

telnet

ldap

ldaps

dict

file

tftp

imap

imaps

pop3

pop3s

smtp

smtps

rtsp

rtmp

rtmpt

rtmpe

rtmpte

rtmps

rtmpts

gopher

all
enable everything

int CURLOPTTYPE_LONG;
int CURLOPTTYPE_OBJECTPOINT;
int CURLOPTTYPE_FUNCTIONPOINT;
int CURLOPTTYPE_OFF_T;
long may be 32 or 64 bits, but we should never depend on anything else but 32

alias CURLOPTTYPE_LONG LONG;
alias CURLOPTTYPE_OBJECTPOINT OBJECTPOINT;
alias CURLOPTTYPE_FUNCTIONPOINT FUNCTIONPOINT;
alias CURLOPTTYPE_OFF_T OFF_T;
name is uppercase CURLOPT_, type is one of the defined CURLOPTTYPE_ number is unique identifier The macro "##" is ISO C, we assume pre-ISO C doesn't support it.

enum CurlOption;

file
This is the FILE * or void * the regular output should be written to.

url
The full URL to get/put

port
Port number to connect to, if other than default.

proxy
Name of proxy to use.

userpwd
"name:password" to use when fetching.

proxyuserpwd
"name:password" to use with proxy.

range
Range to get, specified as an ASCII string.

infile
not used Specified file stream to upload from (use as input):

errorbuffer
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:

writefunction
Function that will be called to store the output (instead of fwrite). The parameters will use fwrite() syntax, make sure to follow them.

readfunction
Function that will be called to read the input (instead of fread). The parameters will use fread() syntax, make sure to follow them.

timeout
Time-out the read operation after this amount of seconds

infilesize
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.

postfields
POST static input fields.

referer
Set the referrer page (needed by some CGIs)

ftpport
Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address.

useragent
Set the User-Agent string (examined by some CGIs)

low_speed_limit
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_time
Set the "low speed time"

resume_from
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.

cookie
Set cookie in request:

httpheader
This points to a linked list of headers, struct curl_slist kind

httppost
This points to a linked list of post entries, struct curl_httppost

sslcert
name of the file keeping your private SSL-certificate

keypasswd
password for the SSL or SSH private key

crlf
send TYPE parameter?

quote
send linked-list of QUOTE commands

writeheader
send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified

cookiefile
point to a file to read the initial cookies from, also enables "cookie awareness"

sslversion
What version to specifically try to use. See CURL_SSLVERSION defines below.

timecondition
What kind of HTTP time condition to use, see defines

timevalue
Time to use with the above condition. Specified in number of seconds since 1 Jan 1970

customrequest
35 = OBSOLETE Custom request, for customizing the get command like

HTTP:
DELETE, TRACE and others

FTP:
to use a different list command

stderr
HTTP request, for odd commands like DELETE, TRACE and others

postquote
38 is not used send linked-list of post-transfer QUOTE commands

writeinfo
Pass a pointer to string of the output using full variable-replacement as described elsewhere.

verbose
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
Append instead of overwrite on upload!

netrc
Specify whether to read the user+password from the .netrc or the URL. This must be one of the CURL_NETRC_* enums below.

followlocation
use Location: Luke!

transfertext
transfer data in text/ASCII format

put
HTTP PUT

progressfunction
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.

progressdata
Data passed to the progress callback

autoreferer
We want the referrer field set automatically when following locations

proxyport
Port of the proxy, can be set in the proxy string as well with: "[host]:[port]"

postfieldsize
size of the POST input data, if strlen() is not good to use

httpproxytunnel
tunnel non-http operations through a HTTP proxy

intrface
Set the interface string to use as outgoing network interface

krblevel
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.

ssl_verifypeer
Set if we should verify the peer in ssl handshake, set 1 to verify.

cainfo
The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true

maxredirs
66 = OBSOLETE 67 = OBSOLETE Maximum number of http redirects to follow

filetime
Pass a long set to 1 to get the date of the requested document (if possible)! Pass a zero to shut it off.

telnetoptions
This points to a linked list of telnet options

maxconnects
Max amount of cached alive connections

closepolicy
What policy to use when closing connections when the cache is filled up

fresh_connect
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.

forbid_reuse
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.

random_file
Set to a file name that contains random data for libcurl to use to seed the random engine when doing SSL connects.

egdsocket
Set to the Entropy Gathering Daemon socket pathname

connecttimeout
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]

headerfunction
Function that will be called to store headers (instead of fwrite). The parameters will use fwrite() syntax, make sure to follow them.

httpget
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.

ssl_verifyhost
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.

cookiejar
Specify which file name to write all known cookies in after completed operation. Set file name to "-" (dash) to make it go to stdout.

ssl_cipher_list
Specify which SSL ciphers to use

http_version
Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below.

ftp_use_epsv
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.

sslcerttype
type of the file keeping your SSL-certificate ("DER", "PEM", "ENG")

sslkey
name of the file keeping your private SSL-key

sslkeytype
type of the file keeping your private SSL-key ("DER", "PEM", "ENG")

sslengine
crypto engine for the SSL-sub system

sslengine_default
set the crypto engine for the SSL-sub system as default the param has no meaning...

dns_use_global_cache
Non-zero value means to use the global dns cache

dns_cache_timeout
DNS cache timeout

prequote
send linked-list of pre-transfer QUOTE commands

debugfunction
set the debug function

debugdata
set the data for the debug function

cookiesession
mark this as start of a cookie session

capath
The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true

buffersize
Instruct libcurl to use a smaller receive buffer

nosignal
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.

share
Provide a CURLShare for mutexing non-ts data

proxytype
indicates type of proxy. accepted values are CURLPROXY_HTTP (default), CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5.

encoding
Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed.

private_opt
Set pointer to private data

http200aliases
Set aliases for HTTP 200 in the HTTP Response header

unrestricted_auth
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.

ftp_use_eprt
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.

httpauth
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.

ssl_ctx_function
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_data
Set the userdata for the ssl context callback function's third argument

ftp_create_missing_dirs
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.

proxyauth
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.

ftp_response_timeout
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.

ipresolve
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.

maxfilesize
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.

infilesize_large
See the comment for INFILESIZE above, but in short, specifies the size of the file being uploaded. -1 means unknown.

resume_from_large
Sets the continuation offset. There is also a LONG version of this; look above for RESUME_FROM.

maxfilesize_large
Sets the maximum size of data that will be downloaded from an HTTP or FTP server. See MAXFILESIZE above for the LONG version.

netrc_file
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.

use_ssl
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

postfieldsize_large
The LARGE version of the standard POSTFIELDSIZE option

tcp_nodelay
Enable/disable the TCP Nagle algorithm

ftpsslauth
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

ioctlfunction

ioctldata

ftp_account
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

cookielist
feed cookies into cookie engine

ignore_content_length
ignore Content-Length

ftp_skip_pasv_ip
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_filemethod
Select "file method" to use when doing FTP, see the curl_ftpmethod above.

localport
Local port number to bind the socket to

localportrange
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.

connect_only
no transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET

conv_from_network_function
Function that will be called to convert from the network encoding (instead of using the iconv calls in libcurl)

conv_to_network_function
Function that will be called to convert to the network encoding (instead of using the iconv calls in libcurl)

conv_from_utf8_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

max_send_speed_large
max_recv_speed_large
if the connection proceeds too quickly then need to slow it down limit-rate: maximum number of bytes per second to send or receive

ftp_alternative_to_user
Pointer to command string to send if USER/PASS fails.

sockoptfunction
callback function for setting socket options

ssl_sessionid_cache
set to 0 to disable session ID re-use for this transfer, default is enabled (== 1)

ssh_auth_types
allowed SSH authentication methods

ssh_public_keyfile
Used by scp/sftp to do public/private key authentication

ftp_ssl_ccc
Send CCC (Clear Command Channel) after authentication

timeout_ms
Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution

http_transfer_decoding
http_content_decoding
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

new_file_perms
new_directory_perms
Permission used when creating new files and directories on the remote server for protocols that support it, SFTP/SCP/FILE

postredir
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

ssh_host_public_key_md5
used by scp/sftp to verify the host's public key

opensocketfunction
opensocketdata
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

copypostfields
POST volatile input fields.

proxy_transfer_mode
set transfer mode (;type=) when doing FTP via an HTTP proxy

seekfunction
seekdata
Callback function for seeking in the input stream

crlfile
CRL file

issuercert
Issuer certificate

address_scope
(IPv6) Address scope

certinfo
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.

username
password
"name" and "pwd" to use when fetching.

proxyusername
proxypassword
"name" and "pwd" to use with Proxy when fetching.

noproxy
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.

tftp_blksize
block size for TFTP transfers

socks5_gssapi_service
Socks Service

socks5_gssapi_nec
Socks Service

protocols
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.

redir_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.

ssh_knownhosts
set the SSH knownhost file name to use

ssh_keyfunction
set the SSH host key callback, must point to a curl_sshkeycallback function

ssh_keydata
set the SSH host key callback custom pointer

mail_from
set the SMTP mail originator

mail_rcpt
set the SMTP mail receiver(s)

ftp_use_pret
FTP:
send PRET before PASV

rtsp_request
RTSP request method (OPTIONS, SETUP, PLAY, etc...)

rtsp_session_id
The RTSP session identifier

rtsp_stream_uri
The RTSP stream URI

rtsp_transport
The Transport: header to use in RTSP requests

rtsp_client_cseq
Manually initialize the client RTSP CSeq for this handle

rtsp_server_cseq
Manually initialize the server RTSP CSeq for this handle

interleavedata
The stream to pass to INTERLEAVEFUNCTION.

interleavefunction
Let the application define a custom write method for RTP data

wildcardmatch
Turn on wildcard matching

chunk_bgn_function
Directory matching callback called before downloading of an individual file (chunk) started

chunk_end_function
Directory matching callback called after the file (chunk) was downloaded, or skipped

fnmatch_function
Change match (fnmatch-like) callback for wildcard matching

chunk_data
Let the application define custom chunk data pointer

fnmatch_data
FNMATCH_FUNCTION user pointer

resolve
send linked-list of name:port:address sets

tlsauth_username
Set a username for authenticated TLS

tlsauth_password
Set a password for authenticated TLS

tlsauth_type
Set authentication type for authenticated TLS

lastentry
the last unused

alias int CURLoption;

CurlOption CURLOPT_SERVER_RESPONSE_TIMEOUT;

enum CurlIpResolve;
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.

whatever
default, resolves addresses to all IP versions that your system allows

v4
resolve to ipv4 addresses

v6
resolve to ipv6 addresses

CurlOption CURLOPT_WRITEDATA;
CurlOption CURLOPT_READDATA;
CurlOption CURLOPT_HEADERDATA;
CurlOption CURLOPT_RTSPHEADER;
three convenient "aliases" that follow the name scheme better

enum CurlHttpVersion;
These enums are for use with the CURLOPT_HTTP_VERSION option.

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

enum CurlRtspReq;
Public API enums for RTSP requests

none

options

describe

announce

setup

play

pause

teardown

get_parameter

set_parameter

record

receive

last

enum CurlNetRcOption;
These enums are for use with the CURLOPT_NETRC option.

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

enum CurlRedir;
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

get_all

post_301

post_302

post_all

enum CurlTimeCond;

none

ifmodsince

ifunmodsince

lastmod

last

alias int curl_TimeCond;

int curl_strequal(char* s1, char* s2);
curl_strequal() and curl_strnequal() are subject for removal in a future libcurl, see lib/README.curlx for details

int curl_strnequal(char* s1, char* s2, size_t n);
ditto curl_strequal() and curl_strnequal() are subject for removal in a future libcurl, see lib/README.curlx for details

struct curl_forms;
structure to be used as parameter for CURLFORM_ARRAY

CURLformoption option;

char* value;

enum CurlFormAdd;
use this for multipart formpost building Returns code for curl_formadd()

Returns:
CURL_FORMADD_OK on success CURL_FORMADD_MEMORY if the FormInfo allocation fails CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form CURL_FORMADD_NULL if a null pointer was given for a char CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated CURL_FORMADD_MEMORY if some allocation for string copying failed. CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array

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;

CURLFORMcode curl_formadd(curl_httppost** httppost, curl_httppost** last_post, ...);
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.

alias extern (C) uint function(void* arg, char* buf, uint len) curl_formget_callback;
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.

int curl_formget(curl_httppost* form, void* arg, curl_formget_callback append);
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.

void curl_formfree(curl_httppost* form);
Name:
curl_formfree()

Description:
Free a multipart formpost previously built with curl_formadd().

char* curl_getenv(char* variable);
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_version();
Name:
curl_version()

Description:
Returns a static ascii string of the libcurl version.

char* curl_easy_escape(void* handle, char* string, int length);
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_escape(char* string, int length);
the previous version:

char* curl_easy_unescape(void* handle, char* string, int length, int* outlength);
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_unescape(char* string, int length);
the previous version

void curl_free(void* p);
Name:
curl_free()

Description:
Provided for de-allocation in the same translation unit that did the allocation. Added in libcurl 7.10

CURLcode curl_global_init(c_long flags);
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_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_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.

void curl_global_cleanup();
Name:
curl_global_cleanup()

Description:
curl_global_cleanup() should be invoked exactly once for each application that uses libcurl

struct curl_slist;
linked-list structure for the CURLOPT_QUOTE option (and other)

curl_slist* curl_slist_append(curl_slist*, char*);
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. linked-list structure for the CURLOPT_QUOTE option (and other)

void curl_slist_free_all(curl_slist*);
Name:
curl_slist_free_all()

Description:
free a previously built curl_slist. linked-list structure for the CURLOPT_QUOTE option (and other)

time_t curl_getdate(char* p, int* unused);
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. linked-list structure for the CURLOPT_QUOTE option (and other)

struct curl_certinfo;
info about the certificate chain, only for OpenSSL builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO linked-list structure for the CURLOPT_QUOTE option (and other)

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"

int CURLINFO_STRING;

int CURLINFO_LONG;

int CURLINFO_DOUBLE;

int CURLINFO_SLIST;

int CURLINFO_MASK;

int CURLINFO_TYPEMASK;

enum CurlInfo;

none

effective_url

response_code

total_time

namelookup_time

connect_time

pretransfer_time

size_upload

size_download

speed_download

speed_upload

header_size

request_size

ssl_verifyresult

filetime

content_length_download

content_length_upload

starttransfer_time

content_type

redirect_time

redirect_count

private_info

http_connectcode

httpauth_avail

proxyauth_avail

os_errno

num_connects

ssl_engines

cookielist

lastsocket

ftp_entry_path

redirect_url

primary_ip

appconnect_time

certinfo

condition_unmet

rtsp_session_id

rtsp_client_cseq

rtsp_server_cseq

rtsp_cseq_recv

primary_port

local_ip

local_port

lastone
Fill in new entries below here!

alias int CURLINFO;

CurlInfo CURLINFO_HTTP_CODE;
CURLINFO_RESPONSE_CODE is the new name for the option previously known as CURLINFO_HTTP_CODE

enum CurlClosePolicy;

none

oldest

least_recently_used

least_traffic

slowest

callback

last

alias int curl_closepolicy;

enum CurlGlobal;

ssl

win32

all

nothing

default_
all

enum CurlLockData;
Setup defines, protos etc for the sharing stuff. Different data locks for a single share

none

share
CURL_LOCK_DATA_SHARE is used internally to say that the locking is just made to change the internal state of the share itself.

cookie

dns

ssl_session

connect

last

alias int curl_lock_data;

enum CurlLockAccess;
Different lock access types

none
unspecified action

shared_access
for read perhaps

single
for write perhaps

last
never use

alias int curl_lock_access;

alias void function(void* handle, int data, int locktype, void* userptr) curl_lock_function;

alias void function(void* handle, int 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;

enum CurlShOption;
pass in a user data pointer used in the lock/unlock callback functions

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;

void* curl_share_init();

CURLSHcode curl_share_setopt(void*, CURLSHoption option, ...);

CURLSHcode curl_share_cleanup(void*);

enum CurlVer;
Structures for querying information about the curl library at runtime.

first

second

third

fourth

last

alias int CURLversion;

CurlVer CURLVERSION_NOW;
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.

struct _N28;

CURLversion age;
age of the returned struct

char* version_;
LIBCURL_VERSION

uint version_num;
LIBCURL_VERSION_NUM

char* host;
OS/host/cpu/machine when configured

int features;
bitmask, see defines below

char* ssl_version;
human readable string

c_long ssl_version_num;
not used anymore, always 0

char* libz_version;
human readable string

char** protocols;
protocols is terminated by an entry with a NULL protoname

char* ares;
The fields below this were added in CURLVERSION_SECOND

char* libidn;
This field was added in CURLVERSION_THIRD

int iconv_ver_num;
These field were added in CURLVERSION_FOURTH Same as 'libiconv_version' if built with HAVE_ICONV

char* libssh_version;
human readable string

alias _N28 curl_version_info_data;

enum CurlVersion;

ipv6
IPv6-enabled

kerberos4
kerberos auth is supported

ssl
SSL options are present

libz
libz features are present

ntlm
NTLM auth is supported

gssnegotiate
Negotiate auth support

dbg
built with debug capabilities

asynchdns
asynchronous dns resolves

spnego
SPNEGO auth

largefile
supports files bigger than 2GB

idn
International Domain Names support

sspi
SSPI is supported

conv
character conversions supported

curldebug
debug memory tracking supported

tlsauth_srp
TLS-SRP auth is supported

_N28* curl_version_info(CURLversion);
Name:
curl_version_info()

Description:
This function returns a pointer to a static copy of the version info struct. See above.

char* curl_easy_strerror(CURLcode);
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.

char* curl_share_strerror(CURLSHcode);
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.

CURLcode curl_easy_pause(void* handle, int bitmask);
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.

enum CurlPause;

recv

recv_cont

send

send_cont

all

cont

void* curl_easy_init();

CURLcode curl_easy_setopt(void* curl, CURLoption option, ...);

CURLcode curl_easy_perform(void* curl);

void curl_easy_cleanup(void* curl);

CURLcode curl_easy_getinfo(void* curl, CURLINFO info, ...);
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.

void* curl_easy_duphandle(void* curl);
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.

void curl_easy_reset(void* 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.

CURLcode curl_easy_recv(void* curl, void* buffer, size_t buflen, uint* n);
Name:
curl_easy_recv()

Description:
Receives data from the connected socket. Use after successful curl_easy_perform() with CURLOPT_CONNECT_ONLY option.

CURLcode curl_easy_send(void* curl, void* buffer, size_t buflen, uint* n);
Name:
curl_easy_send()

Description:
Sends data over the connected socket. Use after successful curl_easy_perform() with CURLOPT_CONNECT_ONLY option.

alias void CURLM;

enum CurlM;

call_multi_perform
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;

CurlM CURLM_CALL_MULTI_SOCKET;
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 CurlMsg;

none

done
This easy handle has completed. 'result' contains the CURLcode of the transfer

last
no used

alias int CURLMSG;

union _N31;

void* whatever;
message-specific data

CURLcode result;
return code for transfer

struct CURLMsg;

CURLMSG msg;
what this message means

CURL* easy_handle;
the handle it concerns

_N31 data;

void* curl_multi_init();
Name:
curl_multi_init()

Desc:
inititalize multi-style curl usage

Returns:
a new CURLM handle to use in all 'curl_multi' functions.

CURLMcode curl_multi_add_handle(void* multi_handle, void* curl_handle);
Name:
curl_multi_add_handle()

Desc:
add a standard curl handle to the multi stack

Returns:
CURLMcode type, general multi error code.

CURLMcode curl_multi_remove_handle(void* multi_handle, void* curl_handle);
Name:
curl_multi_remove_handle()

Desc:
removes a curl handle from the multi stack again

Returns:
CURLMcode type, general multi error code.

alias int fd_set;
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

CURLMcode curl_multi_fdset(void* multi_handle, int* read_fd_set, int* write_fd_set, int* exc_fd_set, int* max_fd);

CURLMcode curl_multi_perform(void* multi_handle, int* running_handles);
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.

CURLMcode curl_multi_cleanup(void* multi_handle);
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.

CURLMsg* curl_multi_info_read(void* multi_handle, int* msgs_in_queue);
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.

char* curl_multi_strerror(CURLMcode);
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.

enum CurlPoll;
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.

none_
jdrewsen - underscored in order not to clash with reserved D symbols

in_

out_

inout_

remove_

alias CURL_SOCKET_BAD CURL_SOCKET_TIMEOUT;

enum CurlCSelect;

in_
jdrewsen - underscored in order not to clash with reserved D symbols

out_

err_

alias extern (C) int function(void* easy, socket_t s, int what, void* userp, void* socketp) curl_socket_callback;
private socket pointer

alias extern (C) int function(void* multi, int timeout_ms, void* userp) curl_multi_timer_callback;
private callback 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. private callback pointer

CURLMcode curl_multi_socket(void* multi_handle, curl_socket_t s, int* running_handles);
ditto

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. private callback pointer

CURLMcode curl_multi_socket_action(void* multi_handle, curl_socket_t s, int ev_bitmask, int* running_handles);
ditto

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. private callback pointer

CURLMcode curl_multi_socket_all(void* multi_handle, int* running_handles);
ditto

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. private callback pointer

CURLMcode curl_multi_timeout(void* multi_handle, int* milliseconds);
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.

enum CurlMOption;

socketfunction
This is the socket callback function pointer

socketdata
This is the argument passed to the socket callback

pipelining
set to 1 to enable pipelining for this multi handle

timerfunction
This is the timer callback function pointer

timerdata
This is the argument passed to the timer callback

maxconnects
maximum number of entries in the connection cache

lastentry

alias int CURLMoption;

CURLMcode curl_multi_setopt(void* multi_handle, CURLMoption option, ...);
Name:
curl_multi_setopt()

Desc:
Sets options for the multi handle.

Returns:
CURLM error code.

CURLMcode curl_multi_assign(void* multi_handle, curl_socket_t sockfd, void* sockp);
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.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

etc.c.sqlite3

string SQLITE_VERSION;
int SQLITE_VERSION_NUMBER;
string SQLITE_SOURCE_ID;
* CAPI3REF: Compile-Time Library Version Numbers

immutable(char)* sqlite3_version;
immutable(char)* sqlite3_libversion();
immutable(char)* sqlite3_sourceid();
int sqlite3_libversion_number();
* CAPI3REF: Run-Time Library Version Numbers

int sqlite3_compileoption_used(const char* zOptName);
immutable(char)* sqlite3_compileoption_get(int N);
* CAPI3REF: Run-Time Library Compilation Options Diagnostics

int sqlite3_threadsafe();
* CAPI3REF: Test To See If The Library Is Threadsafe

struct sqlite3;
* CAPI3REF: Database Connection Handle

alias long sqlite3_int64;

alias ulong sqlite3_uint64;

int sqlite3_close(sqlite3*);
* CAPI3REF: Closing A Database Connection *

alias extern (C) int function(void*, int, char**, char**) sqlite3_callback;
* The type for a callback function. * This is legacy and deprecated. It is included for historical * compatibility and is not documented.

int sqlite3_exec(sqlite3*, const(char)* sql, int function(void*, int, char**, char**) callback, void*, char** errmsg);
* CAPI3REF: One-Step Query Execution Interface

int SQLITE_OK;
* CAPI3REF: Result Codes Successful result

int SQLITE_ERROR;
Ditto SQL error or missing database

int SQLITE_INTERNAL;
Ditto Internal logic error in SQLite

int SQLITE_PERM;
Ditto Access permission denied

int SQLITE_ABORT;
Ditto Callback routine requested an abort

int SQLITE_BUSY;
Ditto The database file is locked

int SQLITE_LOCKED;
Ditto A table in the database is locked

int SQLITE_NOMEM;
Ditto A malloc() failed

int SQLITE_READONLY;
Ditto Attempt to write a readonly database

int SQLITE_INTERRUPT;
Ditto Operation terminated by sqlite3_interrupt()

int SQLITE_IOERR;
Ditto Some kind of disk I/O error occurred

int SQLITE_CORRUPT;
Ditto The database disk image is malformed

int SQLITE_NOTFOUND;
Ditto Unknown opcode in sqlite3_file_control()

int SQLITE_FULL;
Ditto Insertion failed because database is full

int SQLITE_CANTOPEN;
Ditto Unable to open the database file

int SQLITE_PROTOCOL;
Ditto Database lock protocol error

int SQLITE_EMPTY;
Ditto Database is empty

int SQLITE_SCHEMA;
Ditto The database schema changed

int SQLITE_TOOBIG;
Ditto String or BLOB exceeds size limit

int SQLITE_CONSTRAINT;
Ditto Abort due to constraint violation

int SQLITE_MISMATCH;
Ditto Data type mismatch

int SQLITE_MISUSE;
Ditto Library used incorrectly

int SQLITE_NOLFS;
Ditto Uses OS features not supported on host

int SQLITE_AUTH;
Ditto Authorization denied

int SQLITE_FORMAT;
Ditto Auxiliary database format error

int SQLITE_RANGE;
Ditto 2nd parameter to sqlite3_bind out of range

int SQLITE_NOTADB;
Ditto File opened that is not a database file

int SQLITE_ROW;
Ditto sqlite3_step() has another row ready

int SQLITE_DONE;
Ditto sqlite3_step() has finished executing

int SQLITE_IOERR_READ;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_SHORT_READ;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_WRITE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_FSYNC;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_DIR_FSYNC;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_TRUNCATE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_FSTAT;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_UNLOCK;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_RDLOCK;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_DELETE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_BLOCKED;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_NOMEM;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_ACCESS;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_CHECKRESERVEDLOCK;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_LOCK;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_CLOSE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_DIR_CLOSE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_SHMOPEN;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_SHMSIZE;
* CAPI3REF: Extended Result Codes

int SQLITE_IOERR_SHMLOCK;
* CAPI3REF: Extended Result Codes

int SQLITE_LOCKED_SHAREDCACHE;
* CAPI3REF: Extended Result Codes

int SQLITE_BUSY_RECOVERY;
* CAPI3REF: Extended Result Codes

int SQLITE_CANTOPEN_NOTEMPDIR;
* CAPI3REF: Extended Result Codes

int SQLITE_OPEN_READONLY;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_READWRITE;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_CREATE;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_DELETEONCLOSE;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_EXCLUSIVE;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_AUTOPROXY;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_MAIN_DB;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_TEMP_DB;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_TRANSIENT_DB;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_MAIN_JOURNAL;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_TEMP_JOURNAL;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_SUBJOURNAL;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_MASTER_JOURNAL;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_OPEN_NOMUTEX;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_FULLMUTEX;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_SHAREDCACHE;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_PRIVATECACHE;
* CAPI3REF: Flags For File Open Operations Ok for sqlite3_open_v2()

int SQLITE_OPEN_WAL;
* CAPI3REF: Flags For File Open Operations VFS only

int SQLITE_IOCAP_ATOMIC;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC512;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC1K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC2K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC4K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC8K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC16K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC32K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_ATOMIC64K;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_SAFE_APPEND;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_SEQUENTIAL;
* CAPI3REF: Device Characteristics

int SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
* CAPI3REF: Device Characteristics

int SQLITE_LOCK_NONE;
* CAPI3REF: File Locking Levels

int SQLITE_LOCK_SHARED;
* CAPI3REF: File Locking Levels

int SQLITE_LOCK_RESERVED;
* CAPI3REF: File Locking Levels

int SQLITE_LOCK_PENDING;
* CAPI3REF: File Locking Levels

int SQLITE_LOCK_EXCLUSIVE;
* CAPI3REF: File Locking Levels

int SQLITE_SYNC_NORMAL;
* CAPI3REF: Synchronization Type Flags

int SQLITE_SYNC_FULL;
* CAPI3REF: Synchronization Type Flags

int SQLITE_SYNC_DATAONLY;
* CAPI3REF: Synchronization Type Flags

struct sqlite3_file;
* CAPI3REF: OS Interface Open File Handle

struct sqlite3_io_methods;
* CAPI3REF: OS Interface File Virtual Methods Object

int SQLITE_FCNTL_LOCKSTATE;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_GET_LOCKPROXYFILE;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_SET_LOCKPROXYFILE;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_LAST_ERRNO;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_FCNTL_SIZE_HINT;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_FCNTL_CHUNK_SIZE;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_FCNTL_FILE_POINTER;
* CAPI3REF: Standard File Control Opcodes

int SQLITE_FCNTL_SYNC_OMITTED;
* CAPI3REF: Standard File Control Opcodes

struct sqlite3_mutex;
* CAPI3REF: Mutex Handle

alias extern (C) void* function() xDlSymReturn;
alias extern (C) void function() sqlite3_syscall_ptr;
* CAPI3REF: OS Interface Object

int SQLITE_ACCESS_EXISTS;
* CAPI3REF: Flags for the xAccess VFS method

int SQLITE_ACCESS_READWRITE;
* CAPI3REF: Flags for the xAccess VFS method Used by PRAGMA temp_store_directory

int SQLITE_ACCESS_READ;
* CAPI3REF: Flags for the xAccess VFS method Unused

int SQLITE_SHM_UNLOCK;
* CAPI3REF: Flags for the xShmLock VFS method

int SQLITE_SHM_LOCK;
* CAPI3REF: Flags for the xShmLock VFS method

int SQLITE_SHM_SHARED;
* CAPI3REF: Flags for the xShmLock VFS method

int SQLITE_SHM_EXCLUSIVE;
* CAPI3REF: Flags for the xShmLock VFS method

int SQLITE_SHM_NLOCK;
* CAPI3REF: Maximum xShmLock index

int sqlite3_initialize();
int sqlite3_shutdown();
int sqlite3_os_init();
int sqlite3_os_end();
* CAPI3REF: Initialize The SQLite Library

int sqlite3_config(int, ...);
* CAPI3REF: Configuring The SQLite Library

int sqlite3_db_config(sqlite3*, int op, ...);
* CAPI3REF: Configure database connections

struct sqlite3_mem_methods;
* CAPI3REF: Memory Allocation Routines

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()

int SQLITE_CONFIG_SINGLETHREAD;
* CAPI3REF: Configuration Options nil

int SQLITE_CONFIG_MULTITHREAD;
* CAPI3REF: Configuration Options nil

int SQLITE_CONFIG_SERIALIZED;
* CAPI3REF: Configuration Options nil

int SQLITE_CONFIG_MALLOC;
* CAPI3REF: Configuration Options sqlite3_mem_methods*

int SQLITE_CONFIG_GETMALLOC;
* CAPI3REF: Configuration Options sqlite3_mem_methods*

int SQLITE_CONFIG_SCRATCH;
* CAPI3REF: Configuration Options void*, int sz, int N

int SQLITE_CONFIG_PAGECACHE;
* CAPI3REF: Configuration Options void*, int sz, int N

int SQLITE_CONFIG_HEAP;
* CAPI3REF: Configuration Options void*, int nByte, int min

int SQLITE_CONFIG_MEMSTATUS;
* CAPI3REF: Configuration Options boolean

int SQLITE_CONFIG_MUTEX;
* CAPI3REF: Configuration Options sqlite3_mutex_methods*

int SQLITE_CONFIG_GETMUTEX;
* CAPI3REF: Configuration Options sqlite3_mutex_methods*

int SQLITE_CONFIG_LOOKASIDE;
Ditto int int

int SQLITE_CONFIG_PCACHE;
Ditto sqlite3_pcache_methods*

int SQLITE_CONFIG_GETPCACHE;
Ditto sqlite3_pcache_methods*

int SQLITE_CONFIG_LOG;
Ditto xFunc, void*

int SQLITE_DBCONFIG_LOOKASIDE;
* CAPI3REF: Database Connection Configuration Options void* int int

int SQLITE_DBCONFIG_ENABLE_FKEY;
* CAPI3REF: Database Connection Configuration Options int int*

int SQLITE_DBCONFIG_ENABLE_TRIGGER;
* CAPI3REF: Database Connection Configuration Options int int*

int sqlite3_extended_result_codes(sqlite3*, int onoff);
* CAPI3REF: Enable Or Disable Extended Result Codes

sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
* CAPI3REF: Last Insert Rowid

int sqlite3_changes(sqlite3*);
* CAPI3REF: Count The Number Of Rows Modified

int sqlite3_total_changes(sqlite3*);
* CAPI3REF: Total Number Of Rows Modified

void sqlite3_interrupt(sqlite3*);
* CAPI3REF: Interrupt A Long-Running Query

int sqlite3_complete(const char* sql);
int sqlite3_complete16(const void* sql);
* CAPI3REF: Determine If An SQL Statement Is Complete

int sqlite3_busy_handler(sqlite3*, int function(void*, int), void*);
* CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors

int sqlite3_busy_timeout(sqlite3*, int ms);
* CAPI3REF: Set A Busy Timeout

int sqlite3_get_table(sqlite3* db, const(char)* zSql, char*** pazResult, int* pnRow, int* pnColumn, char** pzErrmsg);
* CAPI3REF: Convenience Routines For Running Queries

void sqlite3_free_table(char** result);

alias char* va_list;

char* sqlite3_mprintf(const char*, ...);
* CAPI3REF: Formatted String Printing Functions

void* sqlite3_malloc(int);
void* sqlite3_realloc(void*, int);
void sqlite3_free(void*);
* CAPI3REF: Memory Allocation Subsystem

sqlite3_int64 sqlite3_memory_used();
* CAPI3REF: Memory Allocator Statistics

void sqlite3_randomness(int N, void* P);
* CAPI3REF: Pseudo-Random Number Generator

int sqlite3_set_authorizer(sqlite3*, int function(void*, int, const(char*), const(char*), const(char*), const(char*)) xAuth, void* pUserData);
* CAPI3REF: Compile-Time Authorization Callbacks

int SQLITE_DENY;
* CAPI3REF: Authorizer Return Codes Abort the SQL statement with an error

int SQLITE_IGNORE;
* CAPI3REF: Authorizer Return Codes Don't allow access, but don't generate an error

int SQLITE_CREATE_INDEX;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Index Name Table Name

int SQLITE_CREATE_TABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_CREATE_TEMP_INDEX;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Index Name Table Name

int SQLITE_CREATE_TEMP_TABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_CREATE_TEMP_TRIGGER;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Trigger Name Table Name

int SQLITE_CREATE_TEMP_VIEW;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th View Name NULL

int SQLITE_CREATE_TRIGGER;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Trigger Name Table Name

int SQLITE_CREATE_VIEW;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th View Name NULL

int SQLITE_DELETE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_DROP_INDEX;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Index Name Table Name

int SQLITE_DROP_TABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_DROP_TEMP_INDEX;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Index Name Table Name

int SQLITE_DROP_TEMP_TABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_DROP_TEMP_TRIGGER;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Trigger Name Table Name

int SQLITE_DROP_TEMP_VIEW;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th View Name NULL

int SQLITE_DROP_TRIGGER;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Trigger Name Table Name

int SQLITE_DROP_VIEW;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th View Name NULL

int SQLITE_INSERT;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_PRAGMA;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Pragma Name 1st arg or NULL

int SQLITE_READ;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name Column Name

int SQLITE_SELECT;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th NULL NULL

int SQLITE_TRANSACTION;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Operation NULL

int SQLITE_UPDATE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name Column Name

int SQLITE_ATTACH;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Filename NULL

int SQLITE_DETACH;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Database Name NULL

int SQLITE_ALTER_TABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Database Name Table Name

int SQLITE_REINDEX;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Index Name NULL

int SQLITE_ANALYZE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name NULL

int SQLITE_CREATE_VTABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name Module Name

int SQLITE_DROP_VTABLE;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Table Name Module Name

int SQLITE_FUNCTION;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th NULL Function Name

int SQLITE_SAVEPOINT;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th Operation Savepoint Name

int SQLITE_COPY;
* CAPI3REF: Authorizer Action Codes 3rd ************ 4th No longer used

void* sqlite3_trace(sqlite3*, void function(void*, const(char*)) xTrace, void*);
void* sqlite3_profile(sqlite3*, void function(void*, const(char*), ulong) xProfile, void*);
* CAPI3REF: Tracing And Profiling Functions

void sqlite3_progress_handler(sqlite3*, int, int function(void*), void*);
* CAPI3REF: Query Progress Callbacks

int sqlite3_open(const(char)* filename, sqlite3** ppDb);
int sqlite3_open16(const(void)* filename, sqlite3** ppDb);
int sqlite3_open_v2(const(char)* filename, sqlite3** ppDb, int flags, const(char)* zVfs);
* CAPI3REF: Opening A New Database Connection

int sqlite3_errcode(sqlite3* db);
int sqlite3_extended_errcode(sqlite3* db);
immutable(char)* sqlite3_errmsg(sqlite3*);
immutable(void)* sqlite3_errmsg16(sqlite3*);
* CAPI3REF: Error Codes And Messages

struct sqlite3_stmt;
* CAPI3REF: SQL Statement Object

int sqlite3_limit(sqlite3*, int id, int newVal);
* CAPI3REF: Run-time Limits

int SQLITE_LIMIT_LENGTH;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_SQL_LENGTH;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_COLUMN;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_EXPR_DEPTH;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_COMPOUND_SELECT;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_VDBE_OP;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_FUNCTION_ARG;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_ATTACHED;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_LIKE_PATTERN_LENGTH;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_VARIABLE_NUMBER;
* CAPI3REF: Run-Time Limit Categories

int SQLITE_LIMIT_TRIGGER_DEPTH;
* CAPI3REF: Run-Time Limit Categories

int sqlite3_prepare(sqlite3* db, const(char)* zSql, int nByte, sqlite3_stmt** ppStmt, const(char*)* pzTail);
int sqlite3_prepare_v2(sqlite3* db, const(char)* zSql, int nByte, sqlite3_stmt** ppStmt, const(char*)* pzTail);
int sqlite3_prepare16(sqlite3* db, const(void)* zSql, int nByte, sqlite3_stmt** ppStmt, const(void*)* pzTail);
int sqlite3_prepare16_v2(sqlite3* db, const(void)* zSql, int nByte, sqlite3_stmt** ppStmt, const(void*)* pzTail);
* CAPI3REF: Compiling An SQL Statement

const(char)* sqlite3_sql(sqlite3_stmt* pStmt);
* CAPI3REF: Retrieving Statement SQL

int sqlite3_stmt_readonly(sqlite3_stmt* pStmt);
* CAPI3REF: Determine If An SQL Statement Writes The Database

struct sqlite3_value;
* CAPI3REF: Dynamically Typed Value Object

struct sqlite3_context;
* CAPI3REF: SQL Function Context Object

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void function(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void function(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void function(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
* CAPI3REF: Binding Values To Prepared Statements

int sqlite3_bind_parameter_count(sqlite3_stmt*);
* CAPI3REF: Number Of SQL Parameters

const(char)* sqlite3_bind_parameter_name(sqlite3_stmt*, int);
* CAPI3REF: Name Of A Host Parameter

int sqlite3_bind_parameter_index(sqlite3_stmt*, const char* zName);
* CAPI3REF: Index Of A Parameter With A Given Name

int sqlite3_clear_bindings(sqlite3_stmt*);
* CAPI3REF: Reset All Bindings On A Prepared Statement

int sqlite3_column_count(sqlite3_stmt* pStmt);
* CAPI3REF: Number Of Columns In A Result Set

const(char)* sqlite3_column_name(sqlite3_stmt*, int N);
const(void)* sqlite3_column_name16(sqlite3_stmt*, int N);
* CAPI3REF: Column Names In A Result Set

const(char)* sqlite3_column_database_name(sqlite3_stmt*, int);
const(void)* sqlite3_column_database_name16(sqlite3_stmt*, int);
const(char)* sqlite3_column_table_name(sqlite3_stmt*, int);
const(void)* sqlite3_column_table_name16(sqlite3_stmt*, int);
const(char)* sqlite3_column_origin_name(sqlite3_stmt*, int);
const(void)* sqlite3_column_origin_name16(sqlite3_stmt*, int);
* CAPI3REF: Source Of Data In A Query Result

const(char)* sqlite3_column_decltype(sqlite3_stmt*, int);
const(void)* sqlite3_column_decltype16(sqlite3_stmt*, int);
* CAPI3REF: Declared Datatype Of A Query Result

int sqlite3_step(sqlite3_stmt*);
* CAPI3REF: Evaluate An SQL Statement

int sqlite3_data_count(sqlite3_stmt* pStmt);
* CAPI3REF: Number of columns in a result set

int SQLITE_INTEGER;
* CAPI3REF: Fundamental Datatypes

int SQLITE_FLOAT;
* CAPI3REF: Fundamental Datatypes

int SQLITE_BLOB;
* CAPI3REF: Fundamental Datatypes

int SQLITE_NULL;
* CAPI3REF: Fundamental Datatypes

int SQLITE3_TEXT;
* CAPI3REF: Fundamental Datatypes

const(void)* sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const(char)* sqlite3_column_text(sqlite3_stmt*, int iCol);
const(void)* sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_value* sqlite3_column_value(sqlite3_stmt*, int iCol);
* CAPI3REF: Result Values From A Query

int sqlite3_finalize(sqlite3_stmt* pStmt);
* CAPI3REF: Destroy A Prepared Statement Object

int sqlite3_reset(sqlite3_stmt* pStmt);
* CAPI3REF: Reset A Prepared Statement Object

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);
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);
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: Create Or Redefine SQL Functions

int SQLITE_UTF8;
* CAPI3REF: Text Encodings * * These constant define integer codes that represent the various * text encodings supported by SQLite.

int SQLITE_UTF16LE;
* CAPI3REF: Text Encodings * * These constant define integer codes that represent the various * text encodings supported by SQLite.

int SQLITE_UTF16BE;
* CAPI3REF: Text Encodings * * These constant define integer codes that represent the various * text encodings supported by SQLite.

int SQLITE_UTF16;
Ditto Use native byte order

int SQLITE_ANY;
Ditto sqlite3_create_function only

int SQLITE_UTF16_ALIGNED;
Ditto sqlite3_create_collation only

const(void)* sqlite3_value_blob(sqlite3_value*);
int sqlite3_value_bytes(sqlite3_value*);
int sqlite3_value_bytes16(sqlite3_value*);
double sqlite3_value_double(sqlite3_value*);
int sqlite3_value_int(sqlite3_value*);
sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
const(char)* sqlite3_value_text(sqlite3_value*);
const(void)* sqlite3_value_text16(sqlite3_value*);
const(void)* sqlite3_value_text16le(sqlite3_value*);
const(void)* sqlite3_value_text16be(sqlite3_value*);
int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);
* CAPI3REF: Obtaining SQL Function Parameter Values

void* sqlite3_aggregate_context(sqlite3_context*, int nBytes);
* CAPI3REF: Obtain Aggregate Function Context

void* sqlite3_user_data(sqlite3_context*);
* CAPI3REF: User Data For Functions

sqlite3* sqlite3_context_db_handle(sqlite3_context*);
* CAPI3REF: Database Connection For Functions

void* sqlite3_get_auxdata(sqlite3_context*, int N);
void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void function(void*));
* CAPI3REF: Function Auxiliary Data

alias extern (C) void function(void*) sqlite3_destructor_type;
void function(void*) SQLITE_STATIC;
void function(void*) SQLITE_TRANSIENT;
* CAPI3REF: Constants Defining Special Destructor Behavior

void sqlite3_result_blob(sqlite3_context*, const void*, int, void function(void*));
void sqlite3_result_double(sqlite3_context*, double);
void sqlite3_result_error(sqlite3_context*, const char*, int);
void sqlite3_result_error16(sqlite3_context*, const void*, int);
void sqlite3_result_error_toobig(sqlite3_context*);
void sqlite3_result_error_nomem(sqlite3_context*);
void sqlite3_result_error_code(sqlite3_context*, int);
void sqlite3_result_int(sqlite3_context*, int);
void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
void sqlite3_result_null(sqlite3_context*);
void sqlite3_result_text(sqlite3_context*, const char*, int, void function(void*));
void sqlite3_result_text16(sqlite3_context*, const void*, int, void function(void*));
void sqlite3_result_text16le(sqlite3_context*, const void*, int, void function(void*));
void sqlite3_result_text16be(sqlite3_context*, const void*, int, void function(void*));
void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
void sqlite3_result_zeroblob(sqlite3_context*, int n);
* CAPI3REF: Setting The Result Of An SQL Function

int sqlite3_create_collation(sqlite3*, const(char)* zName, int eTextRep, void* pArg, int function(void*, int, const(void*), int, const(void*)) xCompare);
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);
int sqlite3_create_collation16(sqlite3*, const(void)* zName, int eTextRep, void* pArg, int function(void*, int, const(void*), int, const(void*)) xCompare);
* CAPI3REF: Define New Collating Sequences

int sqlite3_collation_needed(sqlite3*, void*, void function(void*, sqlite3*, int eTextRep, const(char*)));
int sqlite3_collation_needed16(sqlite3*, void*, void function(void*, sqlite3*, int eTextRep, const(void*)));
* CAPI3REF: Collation Needed Callbacks

int sqlite3_key(sqlite3* db, const(void)* pKey, int nKey);

int sqlite3_rekey(sqlite3* db, const(void)* pKey, int nKey);
* 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.

void sqlite3_activate_see(const(char)* zPassPhrase);
* Specify the activation key for a SEE database. Unless * activated, none of the SEE routines will work.

void sqlite3_activate_cerod(const(char)* zPassPhrase);
* Specify the activation key for a CEROD database. Unless * activated, none of the CEROD routines will work.

int sqlite3_sleep(int);
* CAPI3REF: Suspend Execution For A Short Time

char* sqlite3_temp_directory;
* CAPI3REF: Name Of The Folder Holding Temporary Files

int sqlite3_get_autocommit(sqlite3*);
* CAPI3REF: Test For Auto-Commit Mode

sqlite3* sqlite3_db_handle(sqlite3_stmt*);
* CAPI3REF: Find The Database Handle Of A Prepared Statement

sqlite3_stmt* sqlite3_next_stmt(sqlite3* pDb, sqlite3_stmt* pStmt);
* CAPI3REF: Find the next prepared statement

void* sqlite3_commit_hook(sqlite3*, int function(void*), void*);
void* sqlite3_rollback_hook(sqlite3*, void function(void*), void*);
* CAPI3REF: Commit And Rollback Notification Callbacks

void* sqlite3_update_hook(sqlite3*, void function(void*, int, char*, char*, long), void*);
* CAPI3REF: Data Change Notification Callbacks

int sqlite3_enable_shared_cache(int);
* CAPI3REF: Enable Or Disable Shared Pager Cache

int sqlite3_release_memory(int);
* CAPI3REF: Attempt To Free Heap Memory

sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
* CAPI3REF: Impose A Limit On Heap Size

int sqlite3_table_column_metadata(sqlite3* db, const(char)* zDbName, const(char)* zTableName, const(char)* zColumnName, char** pzDataType, char** pzCollSeq, int* pNotNull, int* pPrimaryKey, int* pAutoinc);
* CAPI3REF: Extract Metadata About A Column Of A Table

int sqlite3_load_extension(sqlite3* db, const(char)* zFile, const(char)* zProc, char** pzErrMsg);
* CAPI3REF: Load An Extension

int sqlite3_enable_load_extension(sqlite3* db, int onoff);
* CAPI3REF: Enable Or Disable Extension Loading

int sqlite3_auto_extension(void function() xEntryPoint);
* CAPI3REF: Automatically Load Statically Linked Extensions

void sqlite3_reset_auto_extension();
* CAPI3REF: Reset Automatic Extension Loading

alias extern (C) void function(sqlite3_context*, int, sqlite3_value**) mapFunction;
sqlite3_module">struct sqlite3_module">sqlite3_module;
* 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

struct sqlite3_index_info;
* CAPI3REF: Virtual Table Indexing Information

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

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

int SQLITE_INDEX_CONSTRAINT_EQ;
* CAPI3REF: Virtual Table Constraint Operator Codes

int SQLITE_INDEX_CONSTRAINT_GT;
* CAPI3REF: Virtual Table Constraint Operator Codes

int SQLITE_INDEX_CONSTRAINT_LE;
* CAPI3REF: Virtual Table Constraint Operator Codes

int SQLITE_INDEX_CONSTRAINT_LT;
* CAPI3REF: Virtual Table Constraint Operator Codes

int SQLITE_INDEX_CONSTRAINT_GE;
* CAPI3REF: Virtual Table Constraint Operator Codes

int SQLITE_INDEX_CONSTRAINT_MATCH;
* CAPI3REF: Virtual Table Constraint Operator Codes

int sqlite3_create_module(sqlite3* db, const(char)* zName, const(sqlite3_module)* p, void* pClientData);
int sqlite3_create_module_v2(sqlite3* db, const(char)* zName, const(sqlite3_module)* p, void* pClientData, void function(void*) xDestroy);
* CAPI3REF: Register A Virtual Table Implementation

struct sqlite3_vtab;
* CAPI3REF: Virtual Table Instance Object

const(sqlite3_module)* pModule;
The module for this virtual table

int nRef;
NO LONGER USED

char* zErrMsg;
Error message from sqlite3_mprintf()

struct sqlite3_vtab_cursor;
* CAPI3REF: Virtual Table Cursor Object

sqlite3_vtab* pVtab;
Virtual table of this cursor

int sqlite3_declare_vtab(sqlite3*, const char* zSQL);
* CAPI3REF: Declare The Schema Of A Virtual Table

int sqlite3_overload_function(sqlite3*, const char* zFuncName, int nArg);
* CAPI3REF: Overload A Function For A Virtual Table

struct sqlite3_blob;
* 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.

int sqlite3_blob_open(sqlite3*, const(char)* zDb, const(char)* zTable, const(char)* zColumn, sqlite3_int64 iRow, int flags, sqlite3_blob** ppBlob);
* CAPI3REF: Open A BLOB For Incremental I/O

int sqlite3_blob_reopen(sqlite3_blob*, sqlite3_int64);
* CAPI3REF: Move a BLOB Handle to a New Row

int sqlite3_blob_close(sqlite3_blob*);
* CAPI3REF: Close A BLOB Handle

int sqlite3_blob_bytes(sqlite3_blob*);
* CAPI3REF: Return The Size Of An Open BLOB

int sqlite3_blob_read(sqlite3_blob*, void* Z, int N, int iOffset);
* CAPI3REF: Read Data From A BLOB Incrementally

int sqlite3_blob_write(sqlite3_blob*, const void* z, int n, int iOffset);
* CAPI3REF: Write Data Into A BLOB Incrementally

sqlite3_vfs* sqlite3_vfs_find(const char* zVfsName);
int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
int sqlite3_vfs_unregister(sqlite3_vfs*);
* CAPI3REF: Virtual File System Objects

sqlite3_mutex* sqlite3_mutex_alloc(int);
void sqlite3_mutex_free(sqlite3_mutex*);
void sqlite3_mutex_enter(sqlite3_mutex*);
int sqlite3_mutex_try(sqlite3_mutex*);
void sqlite3_mutex_leave(sqlite3_mutex*);
* CAPI3REF: Mutexes

struct sqlite3_mutex_methods;
* CAPI3REF: Mutex Methods Object

int sqlite3_mutex_held(sqlite3_mutex*);
int sqlite3_mutex_notheld(sqlite3_mutex*);
* CAPI3REF: Mutex Verification Routines

int SQLITE_MUTEX_FAST;
* CAPI3REF: Mutex Types

int SQLITE_MUTEX_RECURSIVE;
* CAPI3REF: Mutex Types

int SQLITE_MUTEX_STATIC_MASTER;
* CAPI3REF: Mutex Types

int SQLITE_MUTEX_STATIC_MEM;
Ditto sqlite3_malloc()

int SQLITE_MUTEX_STATIC_MEM2;
Ditto NOT USED

int SQLITE_MUTEX_STATIC_OPEN;
Ditto sqlite3BtreeOpen()

int SQLITE_MUTEX_STATIC_PRNG;
Ditto sqlite3_random()

int SQLITE_MUTEX_STATIC_LRU;
Ditto lru page list

int SQLITE_MUTEX_STATIC_LRU2;
int SQLITE_MUTEX_STATIC_PMEM;
Ditto NOT USED

sqlite3_mutex* sqlite3_db_mutex(sqlite3*);
* CAPI3REF: Retrieve the mutex for a database connection

int sqlite3_file_control(sqlite3*, const char* zDbName, int op, void*);
* CAPI3REF: Low-Level Control Of Database Files

int sqlite3_test_control(int op, ...);
* CAPI3REF: Testing Interface

int SQLITE_TESTCTRL_FIRST;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_PRNG_SAVE;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_PRNG_RESTORE;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_PRNG_RESET;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_BITVEC_TEST;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_FAULT_INSTALL;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_PENDING_BYTE;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_ASSERT;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_ALWAYS;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_RESERVE;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_OPTIMIZATIONS;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_ISKEYWORD;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_PGHDRSZ;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_SCRATCHMALLOC;
* CAPI3REF: Testing Interface Operation Codes

int SQLITE_TESTCTRL_LAST;
* CAPI3REF: Testing Interface Operation Codes

int sqlite3_status(int op, int* pCurrent, int* pHighwater, int resetFlag);
* CAPI3REF: SQLite Runtime Status

int SQLITE_STATUS_MEMORY_USED;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_PAGECACHE_USED;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_PAGECACHE_OVERFLOW;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_SCRATCH_USED;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_SCRATCH_OVERFLOW;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_MALLOC_SIZE;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_PARSER_STACK;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_PAGECACHE_SIZE;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_SCRATCH_SIZE;
* CAPI3REF: Status Parameters

int SQLITE_STATUS_MALLOC_COUNT;
* CAPI3REF: Status Parameters

int sqlite3_db_status(sqlite3*, int op, int* pCur, int* pHiwtr, int resetFlg);
* CAPI3REF: Database Connection Status

int SQLITE_DBSTATUS_LOOKASIDE_USED;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_CACHE_USED;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_SCHEMA_USED;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_STMT_USED;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_LOOKASIDE_HIT;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL;
* CAPI3REF: Status Parameters for database connections

int SQLITE_DBSTATUS_MAX;
Largest defined DBSTATUS

int sqlite3_stmt_status(sqlite3_stmt*, int op, int resetFlg);
* CAPI3REF: Prepared Statement Status

int SQLITE_STMTSTATUS_FULLSCAN_STEP;
* CAPI3REF: Status Parameters for prepared statements

int SQLITE_STMTSTATUS_SORT;
* CAPI3REF: Status Parameters for prepared statements

int SQLITE_STMTSTATUS_AUTOINDEX;
* CAPI3REF: Status Parameters for prepared statements

struct sqlite3_pcache;
* CAPI3REF: Custom Page Cache Object

struct sqlite3_pcache_methods;
* CAPI3REF: Application Defined Page Cache.

struct sqlite3_backup;
* CAPI3REF: Online Backup Object

sqlite3_backup* sqlite3_backup_init(sqlite3* pDest, const(char)* zDestName, sqlite3* pSource, const(char)* zSourceName);
int sqlite3_backup_step(sqlite3_backup* p, int nPage);
int sqlite3_backup_finish(sqlite3_backup* p);
int sqlite3_backup_remaining(sqlite3_backup* p);
int sqlite3_backup_pagecount(sqlite3_backup* p);
* CAPI3REF: Online Backup API.

int sqlite3_unlock_notify(sqlite3* pBlocked, void function(void** apArg, int nArg) xNotify, void* pNotifyArg);
* CAPI3REF: Unlock Notification

int sqlite3_strnicmp(const char*, const char*, int);
* CAPI3REF: String Comparison

void sqlite3_log(int iErrCode, const char* zFormat, ...);
* CAPI3REF: Error Logging Interface

void* sqlite3_wal_hook(sqlite3*, int function(void*, sqlite3*, const(char*), int), void*);
* CAPI3REF: Write-Ahead Log Commit Hook

int sqlite3_wal_autocheckpoint(sqlite3* db, int N);
* CAPI3REF: Configure an auto-checkpoint

int sqlite3_wal_checkpoint(sqlite3* db, const char* zDb);
* CAPI3REF: Checkpoint a database

int sqlite3_wal_checkpoint_v2(sqlite3* db, const(char)* zDb, int eMode, int* pnLog, int* pnCkpt);
* CAPI3REF: Checkpoint a database

int SQLITE_CHECKPOINT_PASSIVE;
* CAPI3REF: Checkpoint operation parameters

int SQLITE_CHECKPOINT_FULL;
* CAPI3REF: Checkpoint operation parameters

int SQLITE_CHECKPOINT_RESTART;
* CAPI3REF: Checkpoint operation parameters

int sqlite3_rtree_geometry_callback(sqlite3* db, const(char)* zGeom, int function(sqlite3_rtree_geometry*, int nCoord, double* aCoord, int* pRes) xGeom, void* pContext);
* Register a geometry callback named zGeom that can be used as part of an * R-Tree geometry query as follows: * * SELECT ... FROM WHERE MATCH zGeom(... params ...)

struct sqlite3_rtree_geometry;
* A pointer to a structure of the following type is passed as the first * argument to callbacks registered using rtree_geometry_callback().

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

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

etc.c.zlib

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.atomic

The atomic module provides basic support for lock-free concurrent programming.

License:
Boost License 1.0

Authors:
Sean Kelly, Alex Rønne Petersen

Source:
core/atomic.d

Copyright Sean Kelly 2005 - 2010. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.bitop

This module contains a collection of bit-level operations.

License:
Boost License 1.0

Authors:
Don Clugston, Sean Kelly, Walter Bright, Alex Rønne Petersen

Source:
core/bitop.d

pure nothrow @safe int bsf(size_t v);
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.

Example:
 import core.bitop;

 int main()
 {
     assert(bsf(0x21) == 0);
     return 0;
 }

pure nothrow @safe int bsr(size_t v);
Scans the bits in v from the most significant bit to the least significant bit, looking for the first set bit.

Returns:
The bit number of the first bit set. The return value is undefined if v is zero.

Example:
 import core.bitop;

 int main()
 {
     assert(bsr(0x21) == 5);
     return 0;
 }

pure nothrow @safe int bt(in uint* p, size_t bitnum);
Tests the bit.

pure nothrow @safe int btc(uint* p, size_t bitnum);
Tests and complements the bit.

pure nothrow @safe int btr(uint* p, size_t bitnum);
Tests and resets (sets to 0) the bit.

pure nothrow @safe int bts(uint* p, size_t bitnum);
Tests and sets the bit.

Parameters:
uint* p a non-NULL pointer to an array of size_ts.
index 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.

Example:
import std.stdio;
import core.bitop;

int main()
{
    size_t array[2];

    array[0] = 2;
    array[1] = 0x100;

    assert(btc(array, 35) == 0);
    assert(array[0] == 2);
    assert(array[1] == 0x108);

    assert(btc(array, 35) == -1);
    assert(array[0] == 2);
    assert(array[1] == 0x100);

    assert(bts(array, 35) == 0);
    assert(array[0] == 2);
    assert(array[1] == 0x108);

    assert(btr(array, 35) == -1);
    assert(array[0] == 2);
    assert(array[1] == 0x100);

    assert(bt(array, 1) == -1);
    assert(array[0] == 2);
    assert(array[1] == 0x100);

    return 0;
}

pure nothrow @safe uint bswap(uint v);
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.

nothrow @system ubyte inp(uint port_address);
nothrow @system ushort inpw(uint port_address);
nothrow @system uint inpl(uint port_address);
Reads I/O port at port_address.

nothrow @system ubyte outp(uint port_address, ubyte value);
nothrow @system ushort outpw(uint port_address, ushort value);
nothrow @system uint outpl(uint port_address, uint value);
Writes and returns value to I/O port at port_address.

pure nothrow @safe int popcnt(uint x);
Calculates the number of set bits in a 32-bit integer.

pure nothrow @trusted uint bitswap(uint x);
Reverses the order of bits in a 32-bit integer.

Copyright Don Clugston 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.cpuid

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:

  • "Intel(R) 64 and IA-32 Architectures Software Developers Manual, Volume 2A: Instruction Set Reference, A-M" (2007).
  • "AMD CPUID Specification", Advanced Micro Devices, Rev 2.28 (2008).
  • "AMD Processor Recognition Application Note For Processors Prior to AMD Family 0Fh Processors", Advanced Micro Devices, Rev 3.13 (2005).
  • "AMD Geode(TM) GX Processors Data Book", Advanced Micro Devices, Publication ID 31505E, (2005).
  • "AMD K6 Processor Code Optimisation", Advanced Micro Devices, Rev D (2000).
  • "Application note 106: Software Customization for the 6x86 Family", Cyrix Corporation, Rev 1.5 (1998)
  • http://www.datasheetcatalog.org/datasheet/nationalsemiconductor/GX1.pdf
  • "Geode(TM) GX1 Processor Series Low Power Integrated X86 Solution", National Semiconductor, (2002)
  • "The VIA Isaiah Architecture", G. Glenn Henry, Centaur Technology, Inc (2008).
  • http://www.sandpile.org/ia32/cpuid.htm
  • http://www.akkadia.org/drepper/cpumemory.pdf
  • "What every programmer should know about memory", Ulrich Depper, Red Hat, Inc., (2007).
  • "CPU Identification by the Windows Kernel", G. Chappell (2009). http://www.geoffchappell.com/viewer.htm?doc=studies/windows/km/cpu/cx8.htm
  • "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.

License:
Boost License 1.0

Authors:
Don Clugston, Tomas Lindquist Olsen <tomas@famolsen.dk>

Source:
core/cpuid.d

struct CacheInfo;
Cache size and behaviour

size_t size;
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).

ubyte associativity;
Number of ways of associativity, eg: 1 = direct mapped 2 = 2-way set associative 3 = 3-way set associative ubyte.max = fully associative

uint lineSize;
Number of bytes read into the cache when a cache miss occurs.

CacheInfo[5] datacache;
Scheduled for deprecation. Please use dataCaches instead.

nothrow @property @trusted const(CacheInfo)[5u] dataCaches();
The data caches. If there are fewer than 5 physical caches levels, the remaining levels are set to size_t.max (== entire memory space)

nothrow @property @trusted string vendor();
Returns vendor string, for display purposes only. Do NOT use this to determine features! Note that some CPUs have programmable vendorIDs.

nothrow @property @trusted string processor();
Returns processor string, for display purposes only

nothrow @property @trusted bool x87onChip();
Does it have an x87 FPU on-chip?

nothrow @property @trusted bool mmx();
Is MMX supported?

nothrow @property @trusted bool sse();
Is SSE supported?

nothrow @property @trusted bool sse2();
Is SSE2 supported?

nothrow @property @trusted bool sse3();
Is SSE3 supported?

nothrow @property @trusted bool ssse3();
Is SSSE3 supported?

nothrow @property @trusted bool sse41();
Is SSE4.1 supported?

nothrow @property @trusted bool sse42();
Is SSE4.2 supported?

nothrow @property @trusted bool sse4a();
Is SSE4a supported?

nothrow @property @trusted bool aes();
Is AES supported

nothrow @property @trusted bool hasPclmulqdq();
Is pclmulqdq supported

nothrow @property @trusted bool hasRdrand();
Is rdrand supported

nothrow @property @trusted bool avx();
Is AVX supported

nothrow @property @trusted bool vaes();
Is VEX-Encoded AES supported

nothrow @property @trusted bool hasVpclmulqdq();
Is vpclmulqdq supported

nothrow @property @trusted bool fma();
Is FMA supported

nothrow @property @trusted bool fp16c();
Is FP16C supported

nothrow @property @trusted bool avx2();
Is AVX2 supported

nothrow @property @trusted bool hle();
Is HLE (hardware lock elision) supported

nothrow @property @trusted bool rtm();
Is RTM (restricted transactional memory) supported

nothrow @property @trusted bool amd3dnow();
Is AMD 3DNOW supported?

nothrow @property @trusted bool amd3dnowExt();
Is AMD 3DNOW Ext supported?

nothrow @property @trusted bool amdMmx();
Are AMD extensions to MMX supported?

nothrow @property @trusted bool hasFxsr();
Is fxsave/fxrstor supported?

nothrow @property @trusted bool hasCmov();
Is cmov supported?

nothrow @property @trusted bool hasRdtsc();
Is rdtsc supported?

nothrow @property @trusted bool hasCmpxchg8b();
Is cmpxchg8b supported?

nothrow @property @trusted bool hasCmpxchg16b();
Is cmpxchg8b supported?

nothrow @property @trusted bool hasSysEnterSysExit();
Is SYSENTER/SYSEXIT supported?

nothrow @property @trusted bool has3dnowPrefetch();
Is 3DNow prefetch supported?

nothrow @property @trusted bool hasLahfSahf();
Are LAHF and SAHF supported in 64-bit mode?

nothrow @property @trusted bool hasPopcnt();
Is POPCNT supported?

nothrow @property @trusted bool hasLzcnt();
Is LZCNT supported?

nothrow @property @trusted bool isX86_64();
Is this an Intel64 or AMD 64?

nothrow @property @trusted bool isItanium();
Is this an IA64 (Itanium) processor?

nothrow @property @trusted bool hyperThreading();
Is hyperthreading supported?

nothrow @property @trusted uint threadsPerCPU();
Returns number of threads per CPU

nothrow @property @trusted uint coresPerCPU();
Returns number of cores in CPU

nothrow @property @trusted bool preferAthlon();
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:

* Intel P6 (PentiumPro, PII, PIII, PM, Core, Core2). * AMD Athlon (K7, K8, K10). * Intel NetBurst (Pentium 4, Pentium D). * 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:

* Intel Atom 230/330 (family 6, model 0x1C) is an in-order core. * 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?

nothrow @property @trusted bool preferPentium4();
Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code?

nothrow @property @trusted bool preferPentium1();
Does this CPU perform better on Pentium I code than Pentium Pro code?

uint stepping;
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 model;
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 family;
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 numCacheLevels;
This field has been deprecated. Please use cacheLevels instead.

nothrow @property @trusted uint cacheLevels();
The number of cache levels in the CPU.

Copyright Don Clugston 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.exception

The exception module defines all system-level exceptions and provides a mechanism to alter system-level error handling.

License:
Boost License 1.0

Authors:
Sean Kelly and Jonathan M Davis

Source:
core/exception.d

class RangeError: object.Error;
Thrown on a range error.

class AssertError: object.Error;
Thrown on an assert error.

class FinalizeError: object.Error;
Thrown on finalize error.

class HiddenFuncError: object.Error;
Thrown on hidden function error.

class OutOfMemoryError: object.Error;
Thrown on an out of memory error.

class InvalidMemoryOperationError: object.Error;
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 SwitchError: object.Error;
Thrown on a switch error.

class UnicodeException: object.Exception;
Thrown on a unicode conversion error.

void setAssertHandler(errorHandlerType h);
Overrides the default assert hander with a user-supplied version.

Parameters:
errorHandlerType h The new assert handler. Set to null to use the default handler.

void onAssertError(string file = __FILE__, size_t line = __LINE__);
A callback for assert errors in D. The user-supplied assert handler will be called if one has been supplied, otherwise an AssertError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

void onAssertErrorMsg(string file, size_t line, string msg);
A callback for assert errors in D. The user-supplied assert handler will be called if one has been supplied, otherwise an AssertError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.
string msg | An error message supplied by the user.

void onUnittestErrorMsg(string file, size_t line, string 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.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.
string msg | An error message supplied by the user.

void onRangeError(string file = __FILE__, size_t line = __LINE__);
A callback for array bounds errors in D. A RangeError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

Throws:
RangeError.

void onFinalizeError(ClassInfo info, Exception e, string file = __FILE__, size_t line = __LINE__);
A callback for finalize errors in D. A FinalizeError will be thrown.

Parameters:
Exception e The exception thrown during finalization.

Throws:
FinalizeError.

void onHiddenFuncError(Object o);
A callback for hidden function errors in D. A HiddenFuncError will be thrown.

Throws:
HiddenFuncError.

void onOutOfMemoryError();
A callback for out of memory errors in D. An OutOfMemoryError will be thrown.

Throws:
OutOfMemoryError.

void onInvalidMemoryOperationError();
A callback for invalid memory operations in D. An InvalidMemoryOperationError will be thrown.

Throws:
InvalidMemoryOperationError.

void onSwitchError(string file = __FILE__, size_t line = __LINE__);
A callback for switch errors in D. A SwitchError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

Throws:
SwitchError.

void onUnicodeError(string msg, size_t idx, string file = __FILE__, size_t line = __LINE__);
A callback for unicode errors in D. A UnicodeException will be thrown.

Parameters:
string msg | Information about the error.
size_t idx | String index where this error was detected.

Throws:
UnicodeException.

Copyright Sean Kelly 2005 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.memory

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 implementors:
  • On POSIX systems, the signals SIGUSR1 and SIGUSR2 and 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).

  • Registers, the stack, and any other memory locations added through the GC.addRange function are always scanned conservatively. This means that even if a variable is e.g. of type 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.

  • Implementations are free to scan the non-root heap in a precise manner, so that fields of types like float will not be considered relevant when scanning the heap. Thus, casting a GC pointer to an integral type (e.g. 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 GC.BlkAttr.NO_SCAN attribute.

  • 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.

  • 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.

  • 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 GC.BlkAttr.NO_MOVE must not be moved/copied.

  • 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 GC.BlkAttr.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.

  • 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.

  • Implementations are free to assume that GC pointers are only stored on word boundaries. Unaligned pointers may be ignored entirely.

  • 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.

License:
Boost License 1.0

Authors:
Sean Kelly, Alex Rønne Petersen

Source:
core/memory.d

struct GC;
This struct encapsulates all garbage collection functionality for the D programming language.

static nothrow void enable();
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 nothrow void disable();
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 nothrow void collect();
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 nothrow void minimize();
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.

enum BlkAttr;
Elements for a bit field representing memory block attributes. These are manipulated via the getAttr, setAttr, clrAttr functions.

NONE
No attributes set.

FINALIZE
Finalize the data in this block on collect.

NO_SCAN
Do not scan through this block on collect.

NO_MOVE
Do not move this memory block on collect.

APPENDABLE
This block contains the info to allow appending.

NO_INTERIOR
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.

alias .BlkInfo_ BlkInfo;
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.

static nothrow uint getAttr(in void* p);
static pure nothrow uint getAttr(void* p);
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.

Parameters:
void* 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 nothrow uint setAttr(in void* p, uint a);
static pure nothrow uint setAttr(void* p, uint a);
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.

Parameters:
void* p | A pointer to the root of a valid memory block or to null.
uint 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 nothrow uint clrAttr(in void* p, uint a);
static pure nothrow uint clrAttr(void* p, uint 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.

Parameters:
void* p | A pointer to the root of a valid memory block or to null.
uint 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 pure nothrow void* malloc(size_t sz, uint ba = 0);
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.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory or null if insufficient memory is available.

Throws:
OutOfMemoryError on allocation failure.

static pure nothrow BlkInfo qalloc(size_t sz, uint ba = 0);
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.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
Information regarding the allocated memory block or BlkInfo.init on error.

Throws:
OutOfMemoryError on allocation failure.

static pure nothrow void* calloc(size_t sz, uint ba = 0);
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.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory or null if insufficient memory is available.

Throws:
OutOfMemoryError on allocation failure.

static pure nothrow void* realloc(void* p, size_t sz, uint ba = 0);
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.

Parameters:
void* p | A pointer to the root of a valid memory block or to null.
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory on success or null if sz is zero. On failure, the original value of p is returned.

Throws:
OutOfMemoryError on allocation failure.

static pure nothrow size_t extend(void* p, size_t mx, size_t sz);
Requests that the managed memory block referenced by p be extended in place by at least mx bytes, with a desired extension of sz bytes. If an extension of the required size is not possible, if p references memory not originally allocated by this garbage collector, or if p points to the interior of a memory block, no action will be taken.

Parameters:
size_t mx | The minimum extension size in bytes.
size_t sz | The desired extension size in bytes.

Returns:
The size in bytes of the extended memory block referenced by p or zero if no extension occurred.

static nothrow size_t reserve(size_t sz);
Requests that at least sz bytes of memory be obtained from the operating system and marked as free.

Parameters:
size_t sz The desired size in bytes.

Returns:
The actual number of bytes reserved or zero on error.

static pure nothrow void free(void* p);
Deallocates the memory referenced by p. If p is null, no action occurs. If p references memory not originally allocated by this garbage collector, or if it points to the interior of a memory block, no action will be taken. The block will not be finalized regardless of whether the FINALIZE attribute is set. If finalization is desired, use delete instead.

Parameters:
void* p A pointer to the root of a valid memory block or to null.

static nothrow inout(void)* addrOf(inout(void)* p);
static pure nothrow void* addrOf(void* 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.

Parameters:
inout(void)* 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 nothrow size_t sizeOf(in void* p);
static pure nothrow size_t sizeOf(void* 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.

Parameters:
void* 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 nothrow BlkInfo query(in void* p);
static pure nothrow BlkInfo query(void* p);
Returns aggregate information about the memory block containing p. If p references memory not originally allocated by this garbage collector, if p is null, or if the garbage collector does not support this operation, BlkInfo.init will be returned. Typically, support for this operation is dependent on support for addrOf.

Parameters:
void* 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 nothrow void addRoot(in void* 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.

Parameters:
void* 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 nothrow void removeRoot(in void* 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.

Parameters:
void* p A pointer into a GC-managed memory block or null.

static nothrow void addRange(in void* p, size_t sz);
Adds 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 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 not mark this block as live.

Parameters:
void* p | A pointer to a valid memory address or to null.
size_t 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.

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 nothrow void removeRange(in void* p);
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.

Parameters:
void* p A pointer to a valid memory address or to null.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.runtime

The runtime module exposes information specific to the D runtime code.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/runtime.d

struct Runtime;
This struct encapsulates all functionality related to the underlying runtime module for the calling context.

static bool initialize(ExceptionHandler dg = null);
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.

Parameters:
ExceptionHandler dg A delegate which will receive any exception thrown during the initialization process or null if such exceptions should be discarded.

Returns:
true if initialization succeeds and false if initialization fails.

static bool terminate(ExceptionHandler dg = null);
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.

Parameters:
ExceptionHandler dg A delegate which will receive any exception thrown during the termination process or null if such exceptions should be discarded.

Returns:
true if termination succeeds and false if termination fails.

static @property string[] args();
Returns the arguments supplied when the process was started.

Returns:
The arguments supplied when this process was started.

static @property CArgs cArgs();
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:
The arguments supplied when this process was started.

static void* loadLibrary(in char[] name);
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.

Parameters:
char[] name The name of the dynamic library to load.

Returns:
A reference to the library or null on error.

static bool unloadLibrary(void* p);
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.

Parameters:
void* p A reference to the library to unload.

static @property void traceHandler(TraceHandler h);
Overrides the default trace mechanism with s 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.

Parameters:
TraceHandler h The new trace handler. Set to null to use the default handler.

static @property TraceHandler traceHandler();
Gets the current trace handler.

Returns:
The current trace handler or null if no trace handler is set.

static @property void collectHandler(CollectHandler h);
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.

Parameters:
CollectHandler h The new collect handler. Set to null to use the default handler.

static @property CollectHandler collectHandler();
Gets the current collect handler.

Returns:
The current collect handler or null if no trace handler is set.

static @property void moduleUnitTester(ModuleUnitTester h);
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.

Parameters:
ModuleUnitTester h The new unit tester. Set to null to use the default unit tester.

static @property ModuleUnitTester moduleUnitTester();
Gets the current module unit tester.

Returns:
The current module unit tester handler or null if no trace handler is set.

struct CArgs;
This struct stores the unprocessed arguments supplied when the process was started.

bool runModuleUnitTests();
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.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.simd

Builtin SIMD intrinsics

Source:
core/simd.d

License:
Boost License 1.0.

Authors:
Walter Bright,

template Vector(T)
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]

alias __vector(void[16u]) void16;

alias __vector(double[2u]) double2;

alias __vector(float[4u]) float4;

alias __vector(byte[16u]) byte16;

alias __vector(ubyte[16u]) ubyte16;

alias __vector(short[8u]) short8;

alias __vector(ushort[8u]) ushort8;

alias __vector(int[4u]) int4;

alias __vector(uint[4u]) uint4;

alias __vector(long[2u]) long2;

alias __vector(ulong[2u]) ulong2;

alias __vector(void[32u]) void32;

alias __vector(double[4u]) double4;

alias __vector(float[8u]) float8;

alias __vector(byte[32u]) byte32;

alias __vector(ubyte[32u]) ubyte32;

alias __vector(short[16u]) short16;

alias __vector(ushort[16u]) ushort16;

alias __vector(int[8u]) int8;

alias __vector(uint[8u]) uint8;

alias __vector(long[4u]) long4;

alias __vector(ulong[4u]) ulong4;

Copyright Digital Mars 2012. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.thread

The thread module provides support for thread creation and management.

License:
Distributed under the Boost Software License 1.0. (See accompanying file LICENSE)

Authors:
Sean Kelly, Walter Bright, Alex Rønne Petersen

Source:
core/thread.d

alias core.sys.windows.windows.GetCurrentProcessId getpid;
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());

class ThreadException: object.Exception;
Base class for thread exceptions.

class FiberException: object.Exception;
Base class for fiber exceptions.

class 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.

Example:
 class DerivedThread : Thread
 {
     this()
     {
         super( &run );
     }

 private :
     void run()
     {
         printf( "Derived thread running.\n" );
     }
 }

 void threadFunc()
 {
     printf( "Composed thread running.\n" );
 }

 // create instances of each type
 Thread derived = new DerivedThread();
 Thread composed = new Thread( &threadFunc );

 // start both threads
 derived.start();
 composed.start();

this(void function() fn, size_t sz = 0);
Initializes a thread object which is associated with a static D function.

Parameters:
void function() fn | The thread function.
size_t sz | The stack size for this thread.

In:
fn must not be null.

this(void delegate() dg, size_t sz = 0);
Initializes a thread object which is associated with a dynamic D function.

Parameters:
void delegate() dg | The thread function.
size_t sz | The stack size for this thread.

In:
dg must not be null.

final void start();
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 Throwable join(bool rethrow = true);
Waits for this thread to complete. If the thread terminated as the result of an unhandled exception, this exception will be rethrown.

Parameters:
bool 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 @property string name();
Gets the user-readable label for this thread.

Returns:
The name of this thread.

final @property void name(string val);
Sets the user-readable label for this thread.

Parameters:
string val The new name of this thread.

final @property bool isDaemon();
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 void isDaemon(bool val);
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.

Parameters:
bool val The new daemon status for this thread.

final @property bool isRunning();
Tests whether this thread is running.

Returns:
true if the thread is running, false if not.

const int PRIORITY_MIN;
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.

const int PRIORITY_MAX;
The maximum 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.

final @property int priority();
Gets the scheduling priority for the associated thread.

Returns:
The scheduling priority of this thread.

final @property void priority(int val);
Sets the scheduling priority for the associated thread.

Parameters:
int val The new scheduling priority of this thread.

static void sleep(Duration val);
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.

Parameters:
Duration 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

deprecated static void sleep(long period);
Deprecated. It will be removed in December 2012. Please use the version which takes a Duration instead.

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.

Parameters:
long period The minimum duration the calling thread should be suspended, in 100 nanosecond intervals.

In:
period must be non-negative.

Example:
 Thread.sleep( 500_000 );    // sleep for 50 milliseconds
 Thread.sleep( 50_000_000 ); // sleep for 5 seconds

static void yield();
Forces a context switch to occur away from the calling thread.

static Thread getThis();
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[] getAll();
Provides a list of all threads currently being tracked by the system.

Returns:
An array containing references to all threads currently being tracked by the system. The result of deleting any contained objects is undefined.

static int opApply(scope int delegate(ref Thread) dg);
Operates on all threads currently being tracked by the system. The result of deleting any Thread object is undefined.

Parameters:
int delegate(ref Thread) dg The supplied code as a delegate.

Returns:
Zero if all elemented are visited, nonzero if not.

enum Call;

void thread_init();
Initializes the thread module. This function must be called by the garbage collector on startup and before any other thread routines are called.

bool thread_isMainThread();

Thread thread_attachThis();
Thread thread_attachByAddr(Thread.ThreadAddr addr);
Thread thread_attachByAddrB(Thread.ThreadAddr addr, void* bstack);
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.

void thread_detachThis();
void thread_detachByAddr(Thread.ThreadAddr addr);
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.

static Thread thread_findByAddr(Thread.ThreadAddr addr);
Search the list of all threads for a thread with the given thread identifier.

Parameters:
Thread.ThreadAddr addr The thread identifier to search for.

Returns:
The thread object associated with the thread identifier, null if not found.

void thread_setThis(Thread t);
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.

Parameters:
Thread t A reference to the current thread. May be null.

void thread_joinAll();
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.

void thread_suspendAll();
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:
ThreadException if the suspend operation fails for a running thread.

void thread_resumeAll();
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:
ThreadException if the resume operation fails for a running thread.

void thread_processGCMarks(scope rt.tlsgc.IsMarkedDg dg);
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.

Parameters:
hasMarks The probe function. It should return true for pointers into marked memory blocks.

In:
This routine must be called just prior to resuming all threads.

class ThreadGroup;
This class is intended to simplify certain common programming techniques.

final Thread create(void function() fn);
Creates and starts a new Thread object that executes fn and adds it to the list of tracked threads.

Parameters:
void function() fn The thread function.

Returns:
A reference to the newly created thread.

final Thread create(void delegate() dg);
Creates and starts a new Thread object that executes dg and adds it to the list of tracked threads.

Parameters:
void delegate() dg The thread function.

Returns:
A reference to the newly created thread.

final void add(Thread t);
Add t to the list of tracked threads if it is not already being tracked.

Parameters:
Thread t The thread to add.

In:
t must not be null.

final void remove(Thread t);
Removes t from the list of tracked threads. No operation will be performed if t is not currently being tracked by this object.

Parameters:
Thread t The thread to remove.

In:
t must not be null.

final int opApply(scope int delegate(ref Thread) dg);
Operates on all threads currently tracked by this object.

final void joinAll(bool rethrow = true);
Iteratively joins all tracked threads. This function will block add, remove, and opApply until it completes.

Parameters:
bool rethrow Rethrow any unhandled exception which may have caused the current thread to terminate.

Throws:
Any exception not handled by the joined threads.

class Fiber;
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.

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.

this(void function() fn, size_t sz = PAGESIZE * 4);
Initializes a fiber object which is associated with a static D function.

Parameters:
void function() fn | The fiber function.
size_t sz | The stack size for this fiber.

In:
fn must not be null.

this(void delegate() dg, size_t sz = PAGESIZE * 4);
Initializes a fiber object which is associated with a dynamic D function.

Parameters:
void delegate() dg | The fiber function.
size_t sz | The stack size for this fiber.

In:
dg must not be null.

final Object call(bool rethrow = true);
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.

Parameters:
bool 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 void reset();
final void reset(void function() fn);
final void reset(void delegate() dg);
Resets this fiber so that it may be re-used. This routine may 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.

Parameters:
fn | The fiber function.
dg | The fiber function.

In:
This fiber must be in state TERM.

enum State;
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.

HOLD

EXEC

TERM

final const @property State state();
Gets the current state of this fiber.

Returns:
The state of this fiber as an enumerated value.

static void yield();
Forces a context switch to occur away from the calling fiber.

static void yieldAndThrow(Throwable t);
Forces a context switch to occur away from the calling fiber and then throws obj in the calling fiber.

Parameters:
Throwable t The object to throw.

In:
t must not be null.

static Fiber getThis();
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.

Copyright Sean Kelly 2005 - 2012. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.time

Module containing core time functionality, such as Duration (which represents a duration of time).

Various functions take a string (or strings) to represent a unit of time (e.g. 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.

License:
Boost License 1.0.

Authors:
Jonathan M Davis and Kato Shoichi

Source:
core/time.d

struct Duration;
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 core.Thread.sleep.

In std.datetime, it is also used as the result of various arithmetic operations on time points.

Use the dur function or on of its non-generic aliases to create Durations.

You cannot create a duration of months or years because the variable number of days in a month or a year makes it so that you cannot convert between months or years and smaller units without a specific date. Any type or function which handles months or years has other functions for handling those rather than using durations. For instance, std.datetime.Date has addYears and addMonths for adding years and months, rather than creating a duration of years or months and adding that to a std.datetime.Date. If you're dealing with weeks or smaller, however, durations are what you use.

Examples:
assert(dur!"days"(12) == Duration(10_368_000_000_000L));
assert(dur!"hnsecs"(27) == Duration(27));
assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) ==
       std.datetime.Date(2010, 9, 12));

assert(days(-12) == Duration(-10_368_000_000_000L));
assert(hnsecs(-27) == Duration(-27));
assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
       days(-26));

static pure nothrow @property @safe Duration zero();
A Duration of 0. It's shorter than doing something like dur!"seconds"(0) and more explicit than Duration.init.

const pure nothrow @safe int opCmp(Duration rhs);
Compares this Duration with the given Duration.

Returns:
this < rhs | < 0
this == rhs | 0
this > rhs | > 0
this < rhs | < 0
this == rhs | 0
this > rhs | > 0

const pure nothrow @safe Duration opBinary(string op, D)(D rhs);
Adds or subtracts two durations.

The legal types of arithmetic for Duration using this operator are

Duration + Duration --> Duration
Duration - Duration --> Duration
Duration + TickDuration --> Duration
Duration - TickDuration --> Duration
Duration + Duration --> Duration
Duration - Duration --> Duration
Duration + TickDuration --> Duration
Duration - TickDuration --> Duration

Parameters:
rhs The duration to add to or subtract from this Duration.

const pure nothrow @safe Duration opBinaryRight(string op, D)(D lhs);
Adds or subtracts two durations.

The legal types of arithmetic for Duration using this operator are

TickDuration + Duration --> Duration
TickDuration - Duration --> Duration
TickDuration + Duration --> Duration
TickDuration - Duration --> Duration

Parameters:
lhs The TickDuration to add to this Duration or to subtract this Duration from.

pure nothrow @safe Duration opOpAssign(string op, D)(in D rhs);
Adds or subtracts two durations as well as assigning the result to this Duration.

The legal types of arithmetic for Duration using this operator are

Duration + Duration --> Duration
Duration - Duration --> Duration
Duration + TickDuration --> Duration
Duration - TickDuration --> Duration
Duration + Duration --> Duration
Duration - Duration --> Duration
Duration + TickDuration --> Duration
Duration - TickDuration --> Duration

Parameters:
rhs The duration to add to or subtract from this Duration.

const pure nothrow @safe Duration opBinary(string op)(long value);
The legal types of arithmetic for Duration using this operator overload are

Duration * long --> Duration
Duration * long --> Duration

Parameters:
value The value to multiply this Duration by.

pure nothrow @safe Duration opOpAssign(string op)(long value);
The legal types of arithmetic for Duration using this operator overload are

Duration * long --> Duration
Duration * long --> Duration

Parameters:
value The value to multiply this Duration by.

const pure @safe Duration opBinary(string op)(long value);
The legal types of arithmetic for Duration using this operator overload are

Duration / long --> Duration
Duration / long --> Duration

Parameters:
value The value to divide from this duration.

Throws:
TimeException if an attempt to divide by 0 is made.

pure @safe Duration opOpAssign(string op)(long value);
The legal types of arithmetic for Duration using this operator overload are

Duration / long --> Duration
Duration / long --> Duration

Parameters:
value The value to divide from this Duration.

Throws:
TimeException if an attempt to divide by 0 is made.

const pure nothrow @safe Duration opBinaryRight(string op)(long value);
Multiplies an integral value and a Duration.

The legal types of arithmetic for Duration using this operator overload are

long * Duration --> Duration
long * Duration --> Duration

Parameters:
value The number of units to multiply this Duration by.

const pure nothrow @safe Duration opUnary(string op)();
Returns the negation of this Duration.

const pure nothrow @safe TickDuration opCast(T)();
Returns a TickDuration with the same number of hnsecs as this Duration.

const pure nothrow @safe long get(string units)();
Returns the number of the given units in this Duration (minus the larger units).

Examples:
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);

const pure nothrow @property @safe long weeks();
Returns the number of weeks in this Duration (minus the larger units).

Examples:
assert(dur!"weeks"(12).weeks == 12);
assert(dur!"days"(13).weeks == 1);

const pure nothrow @property @safe long days();
Returns the number of days in this Duration (minus the larger units).

Examples:
assert(dur!"weeks"(12).days == 0);
assert(dur!"days"(13).days == 6);
assert(dur!"hours"(49).days == 2);

const pure nothrow @property @safe long hours();
Returns the number of hours in this Duration (minus the larger units).

Examples:
assert(dur!"days"(8).hours == 0);
assert(dur!"hours"(49).hours == 1);
assert(dur!"minutes"(121).hours == 2);

const pure nothrow @property @safe long minutes();
Returns the number of minutes in this Duration (minus the larger units).

Examples:
assert(dur!"hours"(47).minutes == 0);
assert(dur!"minutes"(127).minutes == 7);
assert(dur!"seconds"(121).minutes == 2);

const pure nothrow @property @safe long seconds();
Returns the number of seconds in this Duration (minus the larger units).

Examples:
assert(dur!"minutes"(47).seconds == 0);
assert(dur!"seconds"(127).seconds == 7);
assert(dur!"msecs"(1217).seconds == 1);

const pure nothrow @property @safe FracSec fracSec();
Returns the fractional seconds passed the second in this Duration.

Examples:
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));

const pure nothrow @safe long total(string units)();
Returns the total number of the given units in this Duration. So, unlike get, it does not strip out the larger units.

Examples:
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);

const pure nothrow @safe string toString();
Converts this Duration to a string.

const pure nothrow @property @safe bool isNegative();
Returns whether this Duration is negative.

pure nothrow @safe Duration dur(string units)(long length);
alias dur!("weeks").dur weeks;
alias dur!("days").dur days;
alias dur!("hours").dur hours;
alias dur!("minutes").dur minutes;
alias dur!("seconds").dur seconds;
alias dur!("msecs").dur msecs;
alias dur!("usecs").dur usecs;
alias dur!("hnsecs").dur hnsecs;
alias dur!("nsecs").dur nsecs;
These allow you to construct a Duration from the given time units with the given length.

You can either use the generic function dur and give it the units as a string or use the named aliases.

The possible values for units are "weeks", "days", "hours", "minutes", "seconds", "msecs" (milliseconds), "usecs", (microseconds), "hnsecs" (hecto-nanoseconds, i.e. 100 ns), and "nsecs".

Examples:
// 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);

Parameters:
units | The time units of the Duration (e.g. "days").
length | The number of units in the Duration.

struct TickDuration;
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.

static immutable long ticksPerSec;
The number of ticks that the system clock has in one second.

If ticksPerSec is 0, then then TickDuration failed to get the value of ticksPerSec on the current system, and TickDuration is not going to work. That would be highly abnormal though.

static immutable TickDuration appOrigin;
The tick of the system clock (as a TickDuration) when the application started.

static pure nothrow @property @safe TickDuration zero();
It's the same as TickDuration(0), but it's provided to be consistent with Duration and FracSec, which provide zero properties.

long length;
The number of system ticks in this TickDuration.

You can convert this length into the number of seconds by dividing it by ticksPerSec (or using one the appropriate property function to do it).

const pure nothrow @safe T to(string units, T)();
Converts this TickDuration to the given units as either an integral value or a floating point value.

Parameters:
units | The units to convert to. Accepts "seconds" and smaller only.
T | The type to convert to (either an integral type or a floating point type).

const pure nothrow @property @safe long seconds();
Returns the total number of seconds in this TickDuration.

const pure nothrow @property @safe long msecs();
Returns the total number of milliseconds in this TickDuration.

const pure nothrow @property @safe long usecs();
Returns the total number of microseconds in this TickDuration.

const pure nothrow @property @safe long hnsecs();
Returns the total number of hecto-nanoseconds in this TickDuration.

const pure nothrow @property @safe long nsecs();
Returns the total number of nanoseconds in this TickDuration.

pure nothrow @safe TickDuration from(string units)(long length);
This allows you to construct a TickDuration from the given time units with the given length.

Parameters:
units | The time units of the TickDuration (e.g. "msecs").
length | The number of units in the TickDuration.

const pure nothrow @safe Duration opCast(T)();
Returns a Duration with the same number of hnsecs as this TickDuration.

pure nothrow @safe TickDuration opOpAssign(string op)(TickDuration rhs);
Adds or subtracts two TickDurations as well as assigning the result to this TickDuration.

The legal types of arithmetic for TickDuration using this operator are

TickDuration += TickDuration --> TickDuration
TickDuration -= TickDuration --> TickDuration
TickDuration += TickDuration --> TickDuration
TickDuration -= TickDuration --> TickDuration

Parameters:
rhs The TickDuration to add to or subtract from this TickDuration.

const pure nothrow @safe TickDuration opBinary(string op)(TickDuration rhs);
Adds or subtracts two TickDurations.

The legal types of arithmetic for TickDuration using this operator are

TickDuration + TickDuration --> TickDuration
TickDuration - TickDuration --> TickDuration
TickDuration + TickDuration --> TickDuration
TickDuration - TickDuration --> TickDuration

Parameters:
rhs The TickDuration to add to or subtract from this TickDuration.

const pure nothrow @safe TickDuration opUnary(string op)();
Returns the negation of this TickDuration.

const pure nothrow @safe int opCmp(TickDuration rhs);
operator overloading "<, >, <=, >="

pure nothrow @safe void opOpAssign(string op, T)(T value);
The legal types of arithmetic for TickDuration using this operator overload are

TickDuration * long --> TickDuration
TickDuration * floating point --> TickDuration
TickDuration * long --> TickDuration
TickDuration * floating point --> TickDuration

Parameters:
value The value to divide from this duration.

pure @safe void opOpAssign(string op, T)(T value);
The legal types of arithmetic for TickDuration using this operator overload are

TickDuration / long --> TickDuration
TickDuration / floating point --> TickDuration
TickDuration / long --> TickDuration
TickDuration / floating point --> TickDuration

Parameters:
value The value to divide from this TickDuration.

Throws:
TimeException if an attempt to divide by 0 is made.

const pure nothrow @safe TickDuration opBinary(string op, T)(T value);
The legal types of arithmetic for TickDuration using this operator overload are

TickDuration * long --> TickDuration
TickDuration * floating point --> TickDuration
TickDuration * long --> TickDuration
TickDuration * floating point --> TickDuration

Parameters:
value The value to divide from this TickDuration.

const pure @safe TickDuration opBinary(string op, T)(T value);
The legal types of arithmetic for TickDuration using this operator overload are

TickDuration / long --> TickDuration
TickDuration / floating point --> TickDuration
TickDuration / long --> TickDuration
TickDuration / floating point --> TickDuration

Parameters:
value The value to divide from this TickDuration.

Throws:
TimeException if an attempt to divide by 0 is made.

this(long ticks);
Parameters:
long ticks The number of ticks in the TickDuration.

static @property @trusted TickDuration currSystemTick();
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.

On Windows, QueryPerformanceCounter is used. On Mac OS X, mach_absolute_time is used, while on other Posix systems, clock_gettime is used. If mach_absolute_time or clock_gettime is unavailable, then Posix systems use gettimeofday (the decision is made when TickDuration is compiled), which unfortunately, is not monotonic, but if mach_absolute_time and clock_gettime aren't available, then gettimeofday is the the best that there is.

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:
TimeException if it fails to get the time.

pure nothrow @safe long convert(string from, string to)(long value);
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).

Parameters:
tuFrom | The units of time to covert from.
tuFrom | The units of time to covert type.
value | The value to convert.

Examples:
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);

struct FracSec;
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 Duration or a std.datetime.SysTime without having to worry about whether you're dealing with milliseconds, microseconds, or hnsecs.

FracSec's functions which take time unit strings do accept "nsecs", but because the resolution of Duration and std.datetime.SysTime is hnsecs, you don't actually get precision higher than hnsecs. "nsecs" is accepted merely for convenience. Any values given as nsecs will be converted to hnsecs using convert (which uses truncating division when converting to smaller units).

static pure nothrow @property @safe FracSec zero();
A FracSec of 0. It's shorter than doing something like FracSec.from!"msecs"(0) and more explicit than FracSec.init.

pure @safe FracSec from(string units)(long value);
Create a FracSec from the given units ("msecs", "usecs", or "hnsecs").

Parameters:
units | The units to create a FracSec from.
value | The number of the given units passed the second.

Throws:
TimeException if the given value would result in a FracSec greater than or equal to 1 second or less than or equal to -1 seconds.

const pure nothrow @safe FracSec opUnary(string op)();
Returns the negation of this FracSec.

const pure nothrow @property @safe int msecs();
The value of this FracSec as milliseconds.

pure @property @safe void msecs(int milliseconds);
The value of this FracSec as milliseconds.

Parameters:
int milliseconds The number of milliseconds passed the second.

Throws:
TimeException if the given value is not less than 1 second and greater than a -1 seconds.

const pure nothrow @property @safe int usecs();
The value of this FracSec as microseconds.

pure @property @safe void usecs(int microseconds);
The value of this FracSec as microseconds.

Parameters:
int microseconds The number of microseconds passed the second.

Throws:
TimeException if the given value is not less than 1 second and greater than a -1 seconds.

const pure nothrow @property @safe int hnsecs();
The value of this FracSec as hnsecs.

pure @property @safe void hnsecs(int hnsecs);
The value of this FracSec as hnsecs.

Parameters:
int hnsecs The number of hnsecs passed the second.

Throws:
TimeException if the given value is not less than 1 second and greater than a -1 seconds.

const pure nothrow @property @safe int nsecs();
The value of this FracSec as nsecs.

Note that this does not give you any greater precision than getting the value of this FracSec as hnsecs.

pure @property @safe void nsecs(long nsecs);
The value of this FracSec as nsecs.

Note that this does not give you any greater precision than setting the value of this FracSec as hnsecs.

Parameters:
long nsecs The number of nsecs passed the second.

Throws:
TimeException if the given value is not less than 1 second and greater than a -1 seconds.

const pure nothrow @safe string toString();
Converts this TickDuration to a string.

class TimeException: object.Exception;
Exception type used by core.time.

this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null);
Parameters:
string msg | The message for the exception.
string file | The file where the exception occurred.
size_t line | The line number where the exception occurred.
Throwable next | The previous exception in the chain of exceptions, if any.

Duration abs(Duration duration);
TickDuration abs(TickDuration duration);
Returns the absolute value of a duration.

Copyright 2010 - 2012 | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.vararg

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

License:
Boost License 1.0

Authors:
Walter Bright, Hauke Duden

Source:
core/vararg.d

alias void* va_list;
The base vararg list type.

void va_start(T)(out va_list ap, ref T parmn);
This function initializes the supplied argument pointer for subsequent use by va_arg and va_end.

Parameters:
ap | The argument pointer to initialize.
paramn | The identifier of the rightmost parameter in the function parameter list.

T va_arg(T)(ref va_list ap);
This function returns the next argument in the sequence referenced by the supplied argument pointer. The argument pointer will be adjusted to point to the next arggument in the sequence.

Parameters:
ap The argument pointer.

Returns:
The next argument in the sequence. The result is undefined if ap does not point to a valid argument.

void va_end(va_list ap);
This function cleans up any resources allocated by va_start. It is currently a no-op and exists mostly for syntax compatibility with the variadric argument functions for C.

Parameters:
va_list ap The argument pointer.

void va_copy(out va_list dst, va_list src);
This function copied the argument pointer src to dst.

Parameters:
va_list src | The source pointer.
va_list dst | The destination pointer.

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.barrier

The barrier module provides a primitive for synchronizing the progress of a group of threads.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/barrier.d

class Barrier;
This class represents a barrier across which threads may only travel in groups of a specific size.

this(uint limit);
Initializes a barrier object which releases threads in groups of limit in size.

Parameters:
uint limit The number of waiting threads to release in unison.

Throws:
SyncException on error.

void wait();
Wait for the pre-determined number of threads and then proceed.

Throws:
SyncException on error.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.condition

The condition module provides a primitive for synchronized condition checking.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/condition.d

class Condition;
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.

this(Mutex m);
Initializes a condition object which is associated with the supplied mutex object.

Parameters:
Mutex m The mutex with which this condition will be associated.

Throws:
SyncException on error.

@property Mutex mutex();
Gets the mutex associated with this condition.

Returns:
The mutex associated with this condition.

void wait();
Wait until notified.

Throws:
SyncException on error.

bool wait(Duration val);
Suspends the calling thread until a notification occurs or until the supplied time period has elapsed.

Parameters:
Duration val The time to wait.

In:
val must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

deprecated bool wait(long period);
Deprecated. It will be removed in December 2012. Please use the version which takes a Duration instead.

Suspends the calling thread until a notification occurs or until the supplied time period has elapsed.

Parameters:
long period The time to wait, in 100 nanosecond intervals. This value may be adjusted to equal the maximum wait period supported by the target platform if it is too large.

In:
period must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

void notify();
Notifies one waiter.

Throws:
SyncException on error.

void notifyAll();
Notifies all waiters.

Throws:
SyncException on error.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.config

The config module contains utility routines and configuration information specific to this package.

License:
Boost License 1.0.

Authors:
Sean Kelly

Source:
core/sync/config.d

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.exception

Define base class for synchronization exceptions.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/exception.d

class SyncException: object.Exception;
Base class for synchronization exceptions.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.mutex

The mutex module provides a primitive for maintaining mutually exclusive access.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/mutex.d

class Mutex: object.Object.Monitor;
This class represents a general purpose, recursive mutex.

this();
Initializes a mutex object.

Throws:
SyncException on error.

this(Object o);
Initializes a mutex object and sets it as the monitor for o.

In:
o must not already have a monitor.

@trusted void lock();
If this lock is not already held by the caller, the lock is acquired, then the internal counter is incremented by one.

Throws:
SyncException on error.

@trusted void unlock();
Decrements the internal lock count by one. If this brings the count to zero, the lock is released.

Throws:
SyncException on error.

bool tryLock();
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:
SyncException on error.

Returns:
true if the lock was acquired and false if not.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.rwmutex

The read/write mutex module provides a primitive for maintaining shared read access and mutually exclusive write access.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/rwmutex.d

class ReadWriteMutex;
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.

enum Policy;
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.

PREFER_READERS
Readers get preference. This may starve writers.

PREFER_WRITERS
Writers get preference. This may starve readers.

this(Policy policy = Policy.PREFER_WRITERS);
Initializes a read/write mutex object with the supplied policy.

Parameters:
Policy policy The policy to use.

Throws:
SyncException on error.

@property Policy policy();
Gets the policy used by this mutex.

Returns:
The policy used by this mutex.

@property Reader reader();
Gets an object representing the reader lock for the associated mutex.

Returns:
A reader sub-mutex.

@property Writer writer();
Gets an object representing the writer lock for the associated mutex.

Returns:
A writer sub-mutex.

class Reader: object.Object.Monitor;
This class can be considered a mutex in its own right, and is used to negotiate a read lock for the enclosing mutex.

this();
Initializes a read/write mutex reader proxy object.

@trusted void lock();
Acquires a read lock on the enclosing mutex.

@trusted void unlock();
Releases a read lock on the enclosing mutex.

bool tryLock();
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.

class Writer: object.Object.Monitor;
This class can be considered a mutex in its own right, and is used to negotiate a write lock for the enclosing mutex.

this();
Initializes a read/write mutex writer proxy object.

@trusted void lock();
Acquires a write lock on the enclosing mutex.

@trusted void unlock();
Releases a write lock on the enclosing mutex.

bool tryLock();
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.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

core.sync.semaphore

The semaphore module provides a general use semaphore for synchronization.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/semaphore.d

class Semaphore;
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.

this(uint count = 0);
Initializes a semaphore object with the specified initial count.

Parameters:
uint count The initial count for the semaphore.

Throws:
SyncException on error.

void wait();
Wait until the current count is above zero, then atomically decrement the count by one and return.

Throws:
SyncException on error.

bool wait(Duration val);
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.

Parameters:
period The time to wait.

In:
val must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

deprecated bool wait(long period);
Deprecated. It will be removed in December 2012. Please use the version which takes a Duration instead.

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.

Parameters:
long period The time to wait, in 100 nanosecond intervals. This value may be adjusted to equal to the maximum wait period supported by the target platform if it is too large.

In:
period must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

void notify();
Atomically increment the current count by one. This will notify one waiter, if there are any in the queue.

Throws:
SyncException on error.

bool tryWait();
If the current count is equal to zero, return. Otherwise, atomically decrement the count by one and return true.

Throws:
SyncException on error.

Returns:
true if the count was above zero and false if not.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Windows - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Windows

This describes the D implementation for 32 bit Windows systems. Naturally, Windows specific D features are not portable to other platforms.

Instead of the:

#include <windows.h>

of C, in D there is:

import core.sys.windows.windows;

Calling Conventions

In C, the Windows API calling conventions are __stdcall. In D, it is simply:

extern (Windows)
{
    /* ... function declarations ... */
}

The Windows linkage attribute sets both the calling convention and the name mangling scheme to be compatible with Windows.

For functions that in C would be __declspec(dllimport) or __declspec(dllexport), use the export attribute:

export void func(int foo);

If no function body is given, it's imported. If a function body is given, it's exported.

Windows Executables

Windows GUI applications can be written with D. A sample such can be found in \dmd2\samples\d\winsamp.d

These are required:

  1. Instead of a main function serving as the entry point, a WinMain function is needed.
  2. WinMain must follow this form:
    import core.runtime;
import core.sys.windows.windows;
import std.string;

extern (Windows)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPSTR lpCmdLine, int nCmdShow)
{
    int result;

    void exceptionHandler(Throwable e) {
        throw e;
    }

    try
    {
        Runtime.initialize(&exceptionHandler);
        result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
        Runtime.terminate(&exceptionHandler);
    }
    catch (Throwable e) // catch any uncaught exceptions
    {
        MessageBoxA(null, e.toString().toStringz(), "Error",
                    MB_OK | MB_ICONEXCLAMATION);
        result = 0;     // failed
    }

  return result;
}

int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
              LPSTR lpCmdLine, int nCmdShow)
{
    // ... insert user code here ...
    return 0;
}
    The myWinMain() function is where the user code goes, the rest of WinMain is boilerplate to initialize and shut down the D runtime system.
  3. A .def (Module Definition File) with at least the following two lines in it:
    EXETYPE NT
SUBSYSTEM WINDOWS
    Without those, Win32 will open a text console window whenever the application is run.
  4. The presence of WinMain() is recognized by the compiler causing it to emit a reference to __acrtused_dll and the phobos.lib runtime library.

Windows Programming Examples

A collection of over 140 Windows D programming code examples is available at this Github repository.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Writing Win32 DLLs - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Writing Win32 DLLs

DLLs (Dynamic Link Libraries) are one of the foundations of system programming for Windows. The D programming language enables the creation of several different types of DLLs.

For background information on what DLLs are and how they work Chapter 11 of Jeffrey Richter's book Advanced Windows is indispensible.

This guide will show how to create DLLs of various types with D.

  • DLLs with a C interface
  • DLLs that are COM servers
  • D code calling D code in DLLs

DLLs with a C Interface

A DLL presenting a C interface can connect to any other code in a language that supports calling C functions in a DLL.

DLLs can be created in D in roughly the same way as in C. A DllMain() is required, looking like:

import std.c.windows.windows;
import core.sys.windows.dll;

__gshared HINSTANCE g_hInst;

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
    case DLL_PROCESS_ATTACH:
        g_hInst = hInstance;
        dll_process_attach( hInstance, true );
        break;

    case DLL_PROCESS_DETACH:
        dll_process_detach( hInstance, true );
        break;

    case DLL_THREAD_ATTACH:
        dll_thread_attach( true, true );
        break;

    case DLL_THREAD_DETACH:
        dll_thread_detach( true, true );
        break;
    }
    return true;
}

Notes:

  • DllMain simply forwards to the appropriate helper functions. These setup the runtime, create thread objects for interaction with the garbage collector and initialize thread local storage data.
  • The DLL does not share its runtime or memory with other DLLs.
  • The first boolean argument to the dll-helper functions specify whether all threads should be controlled by the garbage collector. You might need more control over this behaviour if there are threads in the process that must not be suspended. In this case pass false to disable the automatic handling of all threads.
  • The presence of DllMain() is recognized by the compiler causing it to emit a reference to __acrtused_dll and the phobos.lib runtime library.
Link with a .def (Module Definition File) along the lines of:
LIBRARY         MYDLL
DESCRIPTION     'My DLL written in D'

EXETYPE		NT
CODE            PRELOAD DISCARDABLE
DATA            WRITE

EXPORTS
        DllGetClassObject       @2
        DllCanUnloadNow         @3
        DllRegisterServer       @4
        DllUnregisterServer     @5

The functions in the EXPORTS list are for illustration. Replace them with the actual exported functions from MYDLL. Alternatively, use implib. Here's an example of a simple DLL with a function print() which prints a string:

mydll.d:

module mydll;
import std.c.stdio;
export void dllprint() { printf("hello dll world\n"); }

Note: We use printfs in these examples instead of writefln to make the examples as simple as possible.

mydll.def:

LIBRARY "mydll.dll"
EXETYPE NT
SUBSYSTEM WINDOWS
CODE SHARED EXECUTE
DATA WRITE

Put the code above that contains DllMain() into a file dll.d. Compile and link the dll with the following command:

C:>dmd -ofmydll.dll -L/IMPLIB mydll.d dll.d mydll.def
C:>

which will create mydll.dll and mydll.lib. Now for a program, test.d, which will use the dll:

test.d:

import mydll;

int main()
{
   mydll.dllprint();
   return 0;
}

Create an interface file mydll.di that doesn't have the function bodies:

mydll.di:

export void dllprint();
Compile and link with the command:
C:>dmd test.d mydll.lib
C:>
and run:
C:>test
hello dll world
C:>

Memory Allocation

D DLLs use garbage collected memory management. The question is what happens when pointers to allocated data cross DLL boundaries? If the DLL presents a C interface, one would assume the reason for that is to connect with code written in other languages. Those other languages will not know anything about D's memory management. Thus, the C interface will have to shield the DLL's callers from needing to know anything about it.

There are many approaches to solving this problem:

  • Do not return pointers to D gc allocated memory to the caller of the DLL. Instead, have the caller allocate a buffer, and have the DLL fill in that buffer.
  • Retain a pointer to the data within the D DLL so the GC will not free it. Establish a protocol where the caller informs the D DLL when it is safe to free the data.
  • Notify the GC about external references to a memory block by calling GC.addRange.
  • Use operating system primitives like VirtualAlloc() to allocate memory to be transferred between DLLs.
  • Use std.c.stdlib.malloc() (or another non-gc allocator) when allocating data to be returned to the caller. Export a function that will be used by the caller to free the data.

COM Programming

Many Windows API interfaces are in terms of COM (Common Object Model) objects (also called OLE or ActiveX objects). A COM object is an object who's first field is a pointer to a vtbl[], and the first 3 entries in that vtbl[] are for QueryInterface(), AddRef(), and Release().

For understanding COM, Kraig Brockshmidt's Inside OLE is an indispensible resource.

COM objects are analogous to D interfaces. Any COM object can be expressed as a D interface, and every D object with an interface X can be exposed as a COM object X. This means that D is compatible with COM objects implemented in other languages.

While not strictly necessary, the Phobos library provides an Object useful as a super class for all D COM objects, called ComObject. ComObject provides a default implementation for QueryInterface(), AddRef(), and Release().

Windows COM objects use the Windows calling convention, which is not the default for D, so COM functions need to have the attribute extern (Windows). So, to write a COM object:

import std.c.windows.com;

class MyCOMobject : ComObject
{
    extern (Windows):
    ...
}
The sample code includes an example COM client program and server DLL.

D code calling D code in DLLs

Having DLLs in D be able to talk to each other as if they were statically linked together is, of course, very desirable as code between applications can be shared, and different DLLs can be independently developed.

The underlying difficulty is what to do about garbage collection (gc). Each EXE and DLL will have their own gc instance. While these gc's can coexist without stepping on each other, it's redundant and inefficient to have multiple gc's running. The idea explored here is to pick one gc and have the DLLs redirect their gc's to use that one. The one gc used here will be the one in the EXE file, although it's also possible to make a separate DLL just for the gc.

The example will show both how to statically load a DLL, and to dynamically load/unload it.

Starting with the code for the DLL, mydll.d:

/*
 * MyDll demonstration of how to write D DLLs.
 */

import core.runtime;
import std.c.stdio;
import std.c.stdlib;
import std.string;
import std.c.windows.windows;

HINSTANCE   g_hInst;

extern (C)
{
    void  gc_setProxy(void* p);
    void  gc_clrProxy();
}

extern (Windows)
    BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
        case DLL_PROCESS_ATTACH:
        printf("DLL_PROCESS_ATTACH\n");
        Runtime.initialize();
        break;

        case DLL_PROCESS_DETACH:
        printf("DLL_PROCESS_DETACH\n");
        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;
    }
    g_hInst = hInstance;
    return true;
}

export void MyDLL_Initialize(void* gc)
{
    printf("MyDLL_Initialize()\n");
    gc_setProxy(gc);
}

export void MyDLL_Terminate()
{
    printf("MyDLL_Terminate()\n");
    gc_clrProxy();
}

static this()
{
    printf("static this for mydll\n");
}

static ~this()
{
    printf("static ~this for mydll\n");
}

/* --------------------------------------------------------- */

class MyClass
{
    char[] concat(char[] a, char[] b)
    {
    return a ~ " " ~ b;
    }

    void free(char[] s)
    {
    delete s;
    }
}

export MyClass getMyClass()
{
    return new MyClass();
}
DllMain
This is the main entry point for any D DLL. It gets called by the C startup code (for DMC++, the source is \dm\src\win32\dllstart.c). The printf's are placed there so one can trace how it gets called. Notice that the initialization and termination code seen in the earlier DllMain sample code is in this version as well. This is because the same DLL should be usable from both C and D programs, so the same initialization process should work for both.

MyDLL_Initialize
When the DLL is dynamically linked via Runtime.loadLibrary() the runtime makes sure that any initialization steps required by the D program are executed after the library is loaded. If the library is statically linked, this routine is not called by the program, so to make sure the DLL is initialized properly we have to do some of the work ourselves. And because the library is being statically linked, we need a function specific to this DLL to perform the initialization. This function takes one argument, a handle to the caller's gc. We'll see how that handle is obtained later. To pass this handle to the runtime and override the DLL's built-in gc we'll call gc_setProxy(). The function is exported as that is how a function is made visible outside of a DLL.

MyDLL_Terminate
Correspondingly, this function terminates the DLL, and is called prior to unloading it. It has only one job: informing the runtime that the DLL will no longer be using the caller's gc via gc_clrProxy(). This is critical, as the DLL will be unmapped from memory, and if the gc continues to scan its data areas it will cause segment faults.

static this, static ~this
These are examples of the module's static constructor and destructor, here with a print in each to verify that they are running and when.

MyClass
This is an example of a class that can be exported from and used by the caller of a DLL. The concat member function allocates some gc memory, and free frees gc memory.

getMyClass
An exported factory that allocates an instance of MyClass and returns a reference to it.

To build the mydll.dll DLL:
  1. dmd -c mydll -g
    Compiles mydll.d into mydll.obj. -g turns on debug info generation.
  2. dmd mydll.obj mydll.def -g -L/map
    Links mydll.obj into a DLL named mydll.dll. mydll.def is the Module Definition File, and has the contents:
    LIBRARY         MYDLL
DESCRIPTION     'MyDll demonstration DLL'
EXETYPE		NT
CODE            PRELOAD DISCARDABLE
DATA            PRELOAD MULTIPLE
    -g turns on debug info generation, and -L/map generates a map file mydll.map.
  3. implib /noi /system mydll.lib mydll.dll
    Creates an import library mydll.lib suitable for linking in with an application that will be statically loading mydll.dll.

Here's test.d, a sample application that makes use of mydll.dll. There are two versions, one statically binds to the DLL, and the other dynamically loads it.

import core.runtime;
import std.stdio;
import std.gc;

import mydll;

//version=DYNAMIC_LOAD;

version (DYNAMIC_LOAD)
{
    import std.c.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;
        }

        fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass");
        if (fp is null)
        {   printf("error loading symbol getMyClass()\n");
            return 1;
        }

        getMyClass = cast(getMyClass_fp) fp;
        c = (*getMyClass)();
        foo(c);

        if (!Runtime.unloadLibrary(h))
        {   printf("error freeing mydll.dll\n");
            return 1;
        }

        printf("End...\n");
        return 0;
    }
}
else
{   // static link the DLL
    extern (C)
    {
        void* gc_getProxy();
    }

    int main()
    {
    printf("Start Static Link...\n");
    MyDLL_Initialize(gc_getProxy());
    foo(getMyClass());
    MyDLL_Terminate();
    printf("End...\n");
    return 0;
    }
}

void foo(MyClass c)
{
    char[] s;

    s = c.concat("Hello", "world!");
    writefln(s);
    c.free(s);
    delete c;
}

Let's start with the statically linked version, which is simpler. It's compiled and linked with the command:

C:>dmd test mydll.lib -g

Note how it is linked with mydll.lib, the import library for mydll.dll. The code is straightforward, it initializes mydll.lib with a call to MyDLL_Initialize(), passing the handle to test.exe's gc. Then, we can use the DLL and call its functions just as if it were part of test.exe. In foo(), gc memory is allocated and freed both by test.exe and mydll.dll. When we're done using the DLL, it is terminated with MyDLL_Terminate().

Running it looks like this:

C:>test
DLL_PROCESS_ATTACH
Start Static Link...
MyDLL_Initialize()
static this for mydll
Hello world!
MyDLL_Terminate()
static ~this for mydll
End...
C:>

The dynamically linked version is a little harder to set up. Compile and link it with the command:

C:>dmd test -version=DYNAMIC_LOAD -g

The import library mydll.lib is not needed. The DLL is loaded with a call to Runtime.loadLibrary(), and each exported function has to be retrieved via a call to GetProcAddress(). An easy way to get the decorated name to pass to GetProcAddress() is to copy and paste it from the generated mydll.map file under the Export heading. Once this is done, we can use the member functions of the DLL classes as if they were part of test.exe. When done, release the DLL with Runtime.unloadLibrary().

Running it looks like this:

C:>test
Start Dynamic Link...
DLL_PROCESS_ATTACH
static this for mydll
Hello world!
static ~this for mydll
DLL_PROCESS_DETACH
End...
C:>
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


COM Programming - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

COM Programming

COM interfaces are all derived from std.c.windows.com.IUnknown.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Porting 32 Bit Code to 64 Bits - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Porting 32 Bit Code to 64 Bits

Although D is designed to make it easy to port code between 32 and 64 bit modes, being a systems programming language, dependencies can creep in. This guide points out what changes between the two.

Versions

Not all code can be made portable between 32 and 64 bits, and must be versioned. The following works:

version (X86)
    ... 32 bit code ...
else version (X86_64)
    ... 64 bit code ...
else
    static assert("unsupported target")

It is best to write versioning in that manner to give a compile time error on a new target, rather than guessing in advance what, for example, a 64 bit ARM target might require. Experience shows that guesses about how an unfamiliar platform might work always get it wrong. Save those decisions for when one is actually working on a 64 bit ARM.

Size Changes

The size of pointers and references will increase from 4 to 8 bytes. The size_t alias moves from uint to ulong, and the ptrdiff_t alias moves from int to long.

The sizes of compound types based on these will also increase. This includes dynamic arrays, associative arrays, delegates, and class references.

Structs

The size of the struct and the alignment of its fields will change, in order to match the C ABI of the equivalent C struct.

Classes

The size of the class and the alignment of its fields will change, in order to match the alignment most suitable for the 64 bit mode, and in order to accommodate the increased size of pointers and references.

printf

Since printf is a C function, it follows C typing rules. This can have consequences for using them with D types.

D Type | printf format
 | 32 bit | 64 bit
T* | %p | %p
long | %lld | %d
ulong | %llu | %u
ptrdiff_t | %td | %td
size_t | %zu | %zu

For 32 bit code, it was common to use the %.*s format to print strings. This relied on the 32 bit C ABI interpreting the components of a dynamic array as separate length and pointer arguments. 64 bit parameter passing is different, and so the length and pointer should be done explicitly:

string s;
...
printf("s = '%.*s'\n", s);               // 32 bit only
printf("s = '%.*s'\n", s.length, s.ptr); // 32 and 64 bit

Inline Assembly

Naturally, inline assembly for 32 bit code won't work for 64 bit code. The versioning statements to use are:

version (D_InlineAsm_X86)
    ... 32 bit assembler ...
version (D_InlineAsm_X86_64)
    ... 64 bit assembler ...
else
    static assert("unsupported target");

The 64 bit inline assembler uses the syntax found in the Intel and AMD instruction set references.

Variadic Arguments

How variadic arguments work in 64 bits is radically different from 32 bits. They are not a simple array on the stack. You will need to use the functions and templates in std.c.stdarg to access them.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Converting C .h Files to D Modules - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Converting C .h Files to D Modules

While D cannot directly compile C source code, it can easily interface to C code, be linked with C object files, and call C functions in DLLs. The interface to C code is normally found in C .h files. So, the trick to connecting with C code is in converting C .h files to D modules. This turns out to be difficult to do mechanically since inevitably some human judgement must be applied. This is a guide to doing such conversions.

Preprocessor

.h files can sometimes be a bewildering morass of layers of macros, #include files, #ifdef's, etc. D doesn't include a text preprocessor like the C preprocessor, so the first step is to remove the need for it by taking the preprocessed output. For DMC (the Digital Mars C/C++ compiler), the command:
dmc -c program.h -e -l
will create a file program.lst which is the source file after all text preprocessing.

Remove all the #if, #ifdef, #include, etc. statements.

Linkage

Generally, surround the entire module with:
extern (C)
{
     /* ...file contents... */
}
to give it C linkage.

Types

A little global search and replace will take care of renaming the C types to D types. The following table shows a typical mapping for 32 bit C code:

Mapping C type to D type
C type | D type
long double | real
unsigned long long | ulong
long long | long
unsigned long | uint
long | int
unsigned | uint
unsigned short | ushort
signed char | byte
unsigned char | ubyte
wchar_t | wchar or dchar
bool | bool, byte, int
size_t | size_t
ptrdiff_t | ptrdiff_t

NULL

NULL and ((void*)0) should be replaced with null.

Numeric Literals

Any ‘L’ or ‘l’ numeric literal suffixes should be removed, as a C long is (usually) the same size as a D int. Similarly, ‘LL’ suffixes should be replaced with a single ‘L’. Any ‘u’ suffix will work the same in D.

String Literals

In most cases, any ‘L’ prefix to a string can just be dropped, as D will implicitly convert strings to wide characters if necessary. However, one can also replace:
L"string"
with:
"string"w	// for 16 bit wide characters
"string"d	// for 32 bit wide characters

Macros

Lists of macros like:
#define FOO	1
#define BAR	2
#define ABC	3
#define DEF	40
can be replaced with:
enum
{   FOO = 1,
    BAR = 2,
    ABC = 3,
    DEF = 40
}
or with:
const int FOO = 1;
const int BAR = 2;
const int ABC = 3;
const int DEF = 40;
Function style macros, such as:
#define MAX(a,b) ((a) < (b) ? (b) : (a))
can be replaced with functions:
int MAX(int a, int b) { return (a < b) ? b : a; }
The functions, however, won't work if they appear inside static initializers that must be evaluated at compile time rather than runtime. To do it at compile time, a template can be used:
#define GT_DEPTH_SHIFT  (0)
#define GT_SIZE_SHIFT   (8)
#define GT_SCHEME_SHIFT (24)
#define GT_DEPTH_MASK   (0xffU << GT_DEPTH_SHIFT)
#define GT_TEXT         ((0x01) << GT_SCHEME_SHIFT)

/* Macro that constructs a graphtype */
#define GT_CONSTRUCT(depth,scheme,size) \
    ((depth) | (scheme) | ((size) << GT_SIZE_SHIFT))

/* Common graphtypes */
#define GT_TEXT16  GT_CONSTRUCT(4, GT_TEXT, 16)
The corresponding D version would be:
const uint GT_DEPTH_SHIFT  = 0;
const uint GT_SIZE_SHIFT   = 8;
const uint GT_SCHEME_SHIFT = 24;
const uint GT_DEPTH_MASK   = 0xffU << GT_DEPTH_SHIFT;
const uint GT_TEXT         = 0x01 << GT_SCHEME_SHIFT;

// Template that constructs a graphtype
template GT_CONSTRUCT(uint depth, uint scheme, uint size)
{
 // notice the name of the const is the same as that of the template
 const uint GT_CONSTRUCT = (depth | scheme | (size << GT_SIZE_SHIFT));
}

// Common graphtypes
const uint GT_TEXT16 = GT_CONSTRUCT!(4, GT_TEXT, 16);

Declaration Lists

D doesn't allow declaration lists to change the type. Hence:
int *p, q, t[3], *s;
should be written as:
int* p, s;
int q;
int[3] t;

Void Parameter Lists

Functions that take no parameters:
int foo(void);
are in D:
int foo();

Extern Global C Variables

Whenever a global variable is declared in D, it is also defined. But if it's also defined by the C object file being linked in, there will be a multiple definition error. To fix this problem, use the extern storage class. For example, given a C header file named foo.h:
struct Foo { };
struct Foo bar;
It can be replaced with the D modules, foo.d:
struct Foo { }
extern (C)
{
    extern Foo bar;
}

Typedef

alias is the D equivalent to the C typedef:
typedef int foo;
becomes:
alias int foo;

Structs

Replace declarations like:
typedef struct Foo
{   int a;
    int b;
} Foo, *pFoo, *lpFoo;
with:
struct Foo
{   int a;
    int b;
}
alias Foo* pFoo, lpFoo;

Struct Member Alignment

A good D implementation by default will align struct members the same way as the C compiler it was designed to work with. But if the .h file has some #pragma's to control alignment, they can be duplicated with the D align attribute:
#pragma pack(1)
struct Foo
{
    int a;
    int b;
};
#pragma pack()
becomes:
struct Foo
{
  align (1):
    int a;
    int b;
}

Nested Structs

struct Foo
{
    int a;
    struct Bar
    {
    int c;
    } bar;
};

struct Abc
{
    int a;
    struct
    {
    int c;
    } bar;
};
becomes:
struct Foo
{
    int a;
    struct Bar
    {
    int c;
    }
    Bar bar;
}

struct Abc
{
    int a;
    struct
    {
    int c;
    }
}

__cdecl, __pascal, __stdcall

int __cdecl x;
int __cdecl foo(int a);
int __pascal bar(int b);
int __stdcall abc(int c);
becomes:
extern (C) int x;
extern (C) int foo(int a);
extern (Pascal) int bar(int b);
extern (Windows) int abc(int c);

__declspec(dllimport)

__declspec(dllimport) int __stdcall foo(int a);
becomes:
export extern (Windows) int foo(int a);

__fastcall

Unfortunately, D doesn't support the __fastcall convention. Therefore, a shim will be needed, either written in C:
int __fastcall foo(int a);

int myfoo(int a)
{
    return foo(int a);
}
and compiled with a C compiler that supports __fastcall and linked in, or compile the above, disassemble it with obj2asm and insert it in a D myfoo shim with inline assembler.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Real Close to the Machine: Floating Point in D - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Real Close to the Machine: Floating Point in D

Introduction

by Don Clugston

Computers were originally conceived as devices for performing mathematics. The earliest computers spent most of their time solving equations. Although the engineering and scientific community now forms only a miniscule part of the computing world, there is a fantastic legacy from those former times: almost all computers now feature superb hardware for performing mathematical calculations accurately and extremely quickly. Sadly, most programming languages make it difficult for programmers to take full advantage of this hardware. An even bigger problem is the lack of documentation; even for many mathematical programmers, aspects of floating-point arithmetic remain shrouded in mystery.

As a systems programming language, the D programming language attempts to remove all barriers between the programmer and the compiler, and between the programmer and the machine. This philosophy is particularly evident in support for floating-point arithmetic. A personal anecdote may illustrate the importance of having an accurate understanding of the hardware.

My first floating-point nightmare occurred in a C++ program which hung once in every hundred runs or so. I eventually traced the problem to a while loop which occasionally failed to terminate. The essence of the code is shown in Listing 1.

double q[8];
...
int x = 0;
while (x < 8) {
  if ( q[x] >= 0 ) return true;
  if ( q[x] < 0 ) ++x;
}
return false;

Initially, I was completely baffled as to how this harmless-looking loop could fail. But eventually, I discovered that q had not been initialized properly; q[7] contained random garbage. Occasionally, that garbage had every bit set, which mean that q[7] was a Not-a-Number (NaN), a special code which indicates that the value of the variable is nonsense. NaNs were not mentioned in the compiler's documentation - the only information I could find about them was in Intel's assembly instruction set documentation! Any comparison involving a NaN is false, so q[7] was neither >= 0, nor < 0, killing my program. Until that unwelcome discovery, I'd been unaware that NaNs even existed. I had lived in a fool's paradise, mistakenly believing that every floating point number was either positive, negative, or zero.

My experience would have been quite different in D. The "strange" features of floating point have a higher visibility in the language, improving the education of numerical programmers. Uninitialized floating point numbers are initialized to NaN by the compiler, so the problematic loop would fail every time, not intermittently. Numerical programmers in D will generally execute their programs with the 'invalid' floating point exception enabled. Under those circumstances, as soon as the program accessed the uninitialized variable, a hardware exception would occur, summoning the debugger. Easy access to the "strange" features of floating point results in better educated programmers, reduced confusion, faster debugging, better testing, and hopefully, more reliable and correct numerical programs. This article will provide a brief overview of the support for floating point in the D programming language.

Demystifying Floating-Point

D guarantees that all built-in floating-point types conform to IEEE 754 arithmetic, making behaviour entirely predictable (note that this is not the same as producing identical results on all platforms). IEEE 754-2008 is the latest revision of the IEEE 754 Standard for Floating-Point Arithmetic. D is progressing towards full compliance with 754-2008.

The IEEE standard floating point types currently supported by D are float and double. Additionally, D supports the real type, which is either 'IEEE 80-bit extended' if supported by the CPU; otherwise, it is the same as double. In the future, the new types from 754-2008 will be added: quadruple, decimal64, and decimal128.

The characteristics of these types are easily accessible in the language via properties. For example, float.max is the maximum value which can be stored in a float; float.mant_dig is the number of digits (bits) stored in the mantissa.

To make sense of mathematics in D, it's necessary to have a basic understanding of IEEE floating-point arithmetic. Fundamentally, it is a mapping of the infinitely many real numbers onto a small number of bytes. Only 4000 million distinct numbers are representable as an IEEE 32-bit float. Even with such a pathetically small representation space, IEEE floating point arithmetic does a remarkably good job of maintaining the illusion that mathematical real numbers are being used; but it's important to understand when the illusion breaks down.

Most problems arise from the distribution of these representable numbers. The IEEE number line is quite different to the mathematical number line.

     +     +-----------+------------+    ..   +    ..    +----------+----------+     +       #
-infinity -float.max  -1  -float.min_normal   0   float.min_normal  1  float.max infinity  NaN

Notice that half of the IEEE number line lies between -1 and +1. There are 1000 million representable floats between 0 and 0.5, but only 8 million between 0.5 and 1. This has important implications for accuracy: the effective precision is incredibly high near zero. Several examples will be presented where numbers in the range -1 to +1 are treated seperately to take advantage of this.

Notice also the special numbers: ±∞; the so-called "subnormals" between ±float.min_normal and 0, which are represented at reduced precision; the fact that there are TWO zeros, +0 and -0, and finally "NaN"("Not-a-Number"), the nonsense value, which caused so much grief in Listing 1.

Why does NaN exist? It serves a valuable role: it eradicates undefined behaviour from floating-point arithmetic. This makes floating-point completely predictable. Unlike the int type, where 3/0 invokes a hardware division by zero trap handler, possibly ending your program, the floating-point division 3.0/0.0 results in ∞. Numeric overflow (eg, real.max*2) also creates ∞. Depending on the application, ∞ may be a perfectly valid result; more typically, it indicates an error. Nonsensical operations, such as 0.0 / 0.0, result in NaN; but your program does not lose control. At first glance, infinity and NaN may appear unnecessary -- why not just make it an error, just as in the integer case? After all, it is easy to avoid division by zero, simply by checking for a zero denominator before every division. The real difficulty comes from overflow: it is extremely difficult to determine in advance whether an overflow will occur in a multiplication.

Subnormals are necessary to prevent certain anomalies, and preserve important relationships such as: "x - y == 0 if and only if x == y".

Since ∞ can be produced by overflow, both +∞ and -∞ are required. Both +0 and -0 are required in order to preserve identities such as: if x>0, then 1/(1/x) > 0. In almost all other cases, however, there is no difference between +0 and -0.

It's worth noting that these ‘special values’ are usually not very efficient. On x86 machines, for example, a multiplication involving a NaN, an infinity, or a subnormal can be twenty to fifty times slower than an operation on normal numbers. If your numerical code is unexpectedly slow, it's possible that you are inadvertently creating many of these special values. Enabling floating-point exception trapping, described later, is a quick way to confirm this.

One of the biggest factor obscuring what the machine is doing is in the conversion between binary and decimal. You can eliminate this by using the "%a" format when displaying results. This is an invaluable debugging tool, and an enormously helpful aid when developing floating-point algorithms. The 0x1.23Ap+6 hexadecimal floating-point format can also be used in source code for ensuring that your input data is exactly what you intended.

The Quantized Nature of Floating-Point

The fact that the possible values are limited gives access to some operations which are not possible on mathematical real numbers. Given a number x, nextUp(x) gives the next representable number which is greater than x. nextDown(x) gives the next representable number which is less than x.

Numerical analysts often describe errors in terms of "units in the last place"(ulp), a surprisingly subtle term which is often used rather carelessly. [footnote: The most formal definition is found in [J.-M. Muller, "On the definition of ulp(x)",INRIA Technical Report 5504 (2005).]: If x is a real number that lies between two finite consecutive floating-point numbers a and b of type F, without being equal to one of them, then ulp(x)=abs(b-a); otherwise ulp(x) = x*F.epsilon. Moreover, ulp(NaN) is NaN, and ulp(±F.infinity) = ±F.max*F.epsilon.] I prefer a far simpler definition: The difference in ulps between two numbers x and y is is the number of times which you need to call nextUp() or nextDown() to move from x to y. [Footnote: This will not be an integer if either x or y is a real number, rather than a floating point number.] The D library function feqrel(x, y) gives the number of bits which are equal between x and y; it is an easy way to check for loss-of-precision problems.

The quantized nature of floating point has some interesting consequences.

  • ANY mathematical range [a,b), (a,b], or (a,b) can be converted into a range or the form [a,b]. (The converse does not apply: there is no (a,b) equivalent to [-∞, ∞]).
  • A naive binary chop doesn't work correctly. The fact that there are hundreds or thousands of times as many representable numbers between 0 and 1, as there are between 1 and 2, is problematic for divide-and-conquer algorithms. A naive binary chop would divide the interval [0 .. 2] into [0 .. 1] and [1 .. 2]. Unfortunately, this is not a true binary chop, because the interval [0 .. 1] contains more than 99% of the representable numbers from the original interval!

Condition number

Using nextUp, it's easy to approximately calculate the condition number.

real x = 0x1.1p13L;
real u = nextUp(x);

int bitslost = feqrel(x, u) - feqrel(exp(x), exp(u));

This shows that at these huge values of x, a one-bit error in x destroys 12 bits of accuracy in exp(x)! The error has increased by roughly 6000 units in the last place. The condition number is thus 6000 at this value of x.

The semantics of float, double, and real

For the x86 machines which dominate the market, floating point has traditionally been performed on a descendent of the 8087 math coprocessor. These "x87" floating point units were the first to implement IEEE754 arithmetic. The SSE2 instruction set is an alternative for x86-64 processors, but x87 remains the only portable option for floating point 32-bit x86 machines (no 32-bit AMD processors support SSE2).

The x87 is unusual compared to most other floating-point units. It _only_ supports 80-bit operands, henceforth termed "real80". All double and float operands are first converted to 80-bit, all arithmetic operations are performed at 80-bit precision, and the results are reduced to 64-bit or 32-bit precision if required. This means that the results can be significantly more accurate than on a machine which supports at most 64 bit operations. However, it also poses challenges for writing portable code. (Footnote: The x87 allows you to reduce the mantissa length to be the same as 'double or float, but it retains the real80 exponent, which means different results are obtained with subnormal numbers. To precisely emulate double arithmetic slows down floating point code by an order of magnitude).

Apart from the x87 family, the Motorola 68K (but not ColdFire) and Itanium processors are the only ones which support 80-bit floating point.

A similar issue relates to the FMA (fused multiply and accumulate) instruction, which is available on an increasing number of processors, including PowerPC, Itanium, Sparc, and Cell. On such processors, when evaluating expressions such as x*y + z, the x*y is performed at twice the normal precison. Some calculations which would otherwise cause a total loss of precision, are instead calculated exactly. The challenge for a high-level systems programming language is to create an abstraction which provides predictable behaviour on all platforms, but which nonetheless makes good use of the available hardware.

D's approach to this situation arises from the following observations:

  1. It is extremely costly performance-wise to ensure identical behaviour on all processors. In particular, it is crippling for the x87.
  2. Very many programs will only run on a particular processor. It would be unfortunate to deny the use of more accurate hardware, for the sake of portability which would never be required.
  3. The requirements for portability and for high precision are never required simultaneously. If double precision is inadequate, increasing the precision on only some processors doesn't help.
  4. The language should not be tied to particular features of specific processors.

A key design goal is: it should be possible to write code such that, regardless of the processor which is used, the accuracy is never worse than would be obtained on a system which only supports the double type.

(Footnote: real is close to ‘indigenous’ in the Borneo proposal for the Java programming language[Ref Borneo]).

Consider evaluating x*y + z*w, where x, y, z and w are double.

  1. double r1 = x * y + z * w;
  2. double a = x * y; double r2 = a + z * w;
  3. real b = x * y; double r3 = b + z * w;

Note that during optimisation, (2) and (3) may be transformed into (1), but this is implementation-dependent. Case (2) is particularly problematic, because it introduces an additional rounding.

On a "simple" CPU, r1==r2==r3. We will call this value r0. On PowerPC, r2==r3, but r1 may be more accurate than the others, since it enables use of FMA. On x86, r1==r3, which may be more accurate than r0, though not as much as for the PowerPC case. r2, however, may be LESS accurate than r0.

By using real for intermediate values, we are guaranteed that our results are never worse than for a simple CPU which only supports double.

Properties of the Built-in Types

The fundamental floating-point properties are epsilon, min_normal and max. The six integral properties are simply the log2 or log10 of these three.

 | float | double | real80 | quadruple | decimal64 | decimal128
epsilon | 0x1p-23 | 0x1p-52 | 0x1p-63 | 0x1p-112 | 1e-16 (1p-54) | 1e-34 (1p-113)
[min_normal | 0x1p-126 | 0x1p-1022 | 0x1p-16382 | 0x1p-16382 | 1e-383 | 1e-6143
..max) | 0x1p+128 | 0x1p+1024 | 0x1p+16384 | 0x1p+16384 | 1e+385 | 1e+6145
binary properties
mant_dig | 24 | 53 | 64 | 113 | 53 | 112
min_exp | -125 | -1021 | -16381 | -16381 |  |
max_exp | +128 | +1024 | +16384 | +16384 |  |
decimal properties
dig | 6 | 15 | 18 | 33 | 16 | 34
min_10_exp | -37 | -307 | -4932 | -4932 | -382 | -6142
max_10_exp | +38 | +308 | +4932 | +4932 | 385 | +6145

When writing code which should adapt to different CPUs at compile time, use static if with the mant_dig property. For example, static if (real.mant_dig==64) is true if 80-bit reals are available. For binary types, the dig property gives only the minimum number of valid decimal digits. To ensure that that every representable number has a unique decimal representation, two additional digits are required. Similarly, for decimal numbers, mant_dig is a lower bound on the number of valid binary digits.

Useful relations for a floating point type F, where x and y are of type F

  • The smallest representable number is F.min_normal * F.epsilon
  • Any integer between 0 and (1/F.epsilon) can be stored in F without loss of precision. 1/F.epsilon is always a exact power of the base.
  • If a number x is subnormal, x*(1/F.epsilon) is normal, and exponent(x) = exponent(x*(1/F.epsilon)) - (mant_dig-1).
  • x>0 if and only if 1/(1/x) > 0; x<0 if and only if 1/(1/x) < 0.
  • If x-y==0, then x==y && isFinite(x) && isFinite(y). Note that if x==y==infinity, then isNaN(x-y).
  • F.max * F.min_normal = 4.0 for binary types, 10.0 for decimal types.

Addition and subtraction

  • Some loss of precision occurs with x±y if exponent(x)!=exponent(y). The number of digits of precision which are lost is abs(exponent(x)-exponent(y)).
  • x±y has total loss of precision, if and only if (1) abs(x * F.epsilon) > abs(y), in which case x+y == x, x-y == x or (2) abs(y * F.epsilon) > abs(x), in which case x+y == y, x-y == -y
  • Addition is commutative: a + b == b + a.
  • Subtraction is not quite commutative: a - b == -(b - a), but produce +0 and -0 if a==b.
  • Addition is not associative at all.

Multiplication and division

  • Multiplication and division are always at risk of overflow or underflow. For any abs(x) > F.epsilon, there is at least one finite y such that x/y will overflow to ∞. For any abs(x) < F.epsilon, there is at least one finite y such that x/y will underflow to zero. For any abs(x) > 1, there is at least one finite y such that x*y will overflow to ∞. For any abs(x) < 1, there is at least one finite y such that x*y will underflow to zero.
  • x*x will overflow if abs(x)>sqrt(F.max), and underflow to zero if abs(x) < sqrt(F.min_normal*F.epsilon)
  • Multiplication is commutative. a * b == b * a
    • .
  • Multiplication is not associative in general: a*(b*c) != (a*b)*c, because (1) there is a risk of overflow or underflow and (2) b*c may be an exact calculation, so that a*(b*c) contains only one round-off error, whereas (a*b)*c contains two. The roundoff errors may therefore accumulate at the rate of just under 1 ulp per multiplication.
  • However, a limited form of associativity is possible if the type used for intermediate results is larger than any of the operands (which happens on x87 and Itanium machines). If R is the intermediate type, and F is the type being multiplied, up to min(R.max_exp/F.max_exp, R.epsilon/F.epsilon) values of type F can be multiplied together in any order without influencing the result. For example, if R is double, multiplication of 8 floats f1*f2*f3*f4*f5*f6*f7*f8 is completely associative. On x87, 130 floats can be safely multiplied together in any order, and 16 doubles can similarly be multiplied together safely. Strict distributivity does not hold even under these circumstances, as it may destroy the sign of -0.
  • The distributive law almost never holds. For example, 4*x + 6*x != 10*x if x==nextDown(1.5). a*x + b*x == (a+b)*x for all x only if the operations a*x, b*x, and (a+b) are all exact operations, which is true only if a and b are exact powers of 2. Even then, if a==-b and x==-0, then a*x+b*x==0.0, (a+b)*x==-0.0.
  • Performing a division by multiplication by the reciprocal returns a result which (in round-to-nearest mode) is at most 1.5 ulps from the correctly rounded result. For almost any denominator, the rounding is incorrect (>0.5ulps) for 27% of numerators. [Ref: N. Brisebarre, J-M Muller, and S.K. Raina, "Accelerating Correctly Rounded Floating-Point Division when the Divisor Is Known in Advance", IEEE Trans. on Computers, Vol 53, pp 1069-1072 (2004)].

Powers and logarithms

  • F.mant_dig = -log2(F.epsilon) for binary types;
  • F.dig = -log10(F.epsilon) for decimal types.
  • F.max = exp2(F.max_exp*(1-F.epsilon)) for binary types;
  • F.max = exp10(F.max_10_exp*(1-F.epsilon)) for decimal types.
  • For any positive finite x, F.min_exp - F.mant_dig <= log2(x) < F.max_exp for binary types, F.min_10_exp - F.dig <= log10(x) < F.max_10_exp for decimal types
  • exp2(x) == 0 if x < F.min_exp - F.mant_dig, exp2(x) == infinity if x >= F.max_exp

NaN payloads

According to the IEEE 754 standard, a ‘payload’ can be stored in the mantissa of a NaN. This payload can contain information about how or why it was generated. Historically, almost no programming languages have ever made use of this potentially powerful feature. In D, this payload consists of a positive integer.

  • real NaN(ulong payload) -- create a NaN with a "payload", where the payload is a ulong.
  • ulong getNaNPayload(real x) -- returns the integer payload. Note that if narrowing conversions have occured, the high-order bits may have changed.

Never store a pointer as an integer payload inside a NaN. The garbage collector will not be able to find it!

NCEG comparison operations

As well as the usual <, >, <=, and >= comparison operators, D also supports the "NCEG" operators. Most of them are the direct negation of the ordinary operators. Additionally, <>, <>=, !<>, and !<>= are provided. These 8 new operators are different from the normal operators only when a NaN is involved, so for the most part they are quite obscure. They are useful mainly in eliminating the possibility of NaN before beginning a calculation. The most useful relationships are probably:

  • x <>= y is the same as !isNaN(x) && !isNaN(y), (except that signalling NaNs may be triggered by <>=).
  • x !<>= y is the same as isNaN(x) || isNaN(y).
If y is any compile-time constant (eg 0), these reduce to !isNaN(x) and isNaN(x). Note that x==x is the same as !isNaN(x), and x!=x is the same as isNaN(x). abs(x) !< x.infinity is the same as isNaN(x) || isInfinity(x) The above relationships are useful primarily because they can be used in compile time functions. Very few uses are known for the remaining NCEG operators.

The IEEE Rounding Modes

The rounding mode is controlled within a scope. Rounding mode will be restored to its previous state at the end of that scope. Four rounding modes can be set. The default mode, Round to nearest, is the most statistically accurate, but the least intuitive. In the event of tie, the result is rounded to an even number.

Rounding mode | rndint(4.5) | rndint(5.5) | rndint(-4.5) | Notes
Round to nearest | 4 | 6 | -4 | Ties round to an even number
Round down | 4 | 5 | -5 |
Round up | 5 | 6 | -4 |
Round to zero | 4 | 5 | -4 |

There are very few reasons for changing the rounding mode. The round-up and round-down modes were created specifically to allow fast implementations of interval arithmetic; they are crucial to certain libraries, but rarely used elsewhere. The round-to-zero mode is used for casting floating-point numbers to integers. Since mode switching is slow, especially on Intel machines, it may be useful to switch to round-to-zero mode, in order to exactly duplicate the behaviour of cast(int) in an inner loop.

The only other commonly cited reason for changing the rounding mode is as a simple check for numerical stability: if the calculation produces wildly different results when the rounding mode is changed, it's a clear sign that it is suffering from round-off errors.

The IEEE Exception Status Flags

All IEEE-compiliant processors include special status bits that indicate when "weird" things have happened that programs might want to know about. For example, ieeeFlags.divideByZero tells if any infinities have been created by dividing by zero. They are 'sticky' bits: once they have been set, they remain set until explicitly cleared. By only checking this once at the end of a calculation, it may be possible to avoid comparing thousands of comparisions that are almost never going to fail.

Here's a list of the weird things that can be detected:

invalid
This is set if any NaN's have been generated. This can happen with ∞ - ∞, ∞ * 0, 0 * ∞, 0/0, ∞/∞, ∞%∞, or x%0, for any number x. Several other operations, such as sqrt(-1), can also generate a NaN. The invalid condition is also set when a 'signalling NaN' is accessed, indicating use of an uninitialized variable. This almost always indicates a programming error.
overflow
Set if ∞ was generated by adding or multiplying two numbers that were so large that the sum was greater than real.max. This almost always indicates that the result is incorrect; and corrective action needs to be taken.
divisionByZero
Set if ±∞ was generated by dividing by zero. This usually indicates a programming error, but not always; some types of calculations return correct results even when division by zero occurs. (For example, 1/(1+ 1/x) == 0 if x == 0). Note that division by a tiny, almost-zero number also produces an infinite result, but sets the overflow flag rather than the divisionByZero flag.
underflow
This happens if two numbers are subtracted or divided and are so tiny that the result lost precision because it was subnormal. Extreme underflow produces a zero result. Underflow almost never creates problems, and can usually be ignored.
inexact
This indicates that rounding has occurred. Almost all floating point operations set this flag! It was apparently included in the hardware to support some arcane tricks used in the pioneering days of numerical analysis. It can always be ignored.

Floating-point traps can be enabled for any of the categories listed above. When enabled, a hardware exception will be generated. This can be an invaluable debugging aid. A more advanced usage, not yet supported on any platform(!) is to provide a nested function to be used as a hardware exception handler. This is most useful for the overflow and underflow exceptions.

Floating point and ‘pure nothrow’

Every floating point operation, even the most trivial, is affected by the floating-point rounding state, and writes to the sticky flags. The status flags and control state are thus 'hidden variables', potentially affecting every pure function; and if the floating point traps are enabled, any floating point operation can generate a hardware exception. D provides a facility for the floating-point control mode and exception flags to be usable in limited circumstances even when pure and nothrow functions are called.

[TODO: I've made two proposals, but I haven't persauded Walter yet!].

Conclusion

Although D is a general-purpose programming language and supports many high-level concepts, it gives direct and convenient access to almost all features of modern floating-point hardware. This makes it an excellent language for development of robust, high-performance numerical code. It is also a language which encourages a deep understanding of the machine, making it fertile ground for innovation and for developing new algorithms.

References and Further Reading

  1. "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
  2. "An Interview with the Old Man of Floating-Point: Reminiscences elicited from William Kahan by Charles Severance"
  3. N. Brisebarre, J-M Muller, and S.K. Raina, "Accelerating Correctly Rounded Floating-Point Division when the Divisor Is Known in Advance", IEEE Trans. on Computers, Vol 53, pp 1069-1072 (2004).
  4. "The Borneo language"
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Exception Safety - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Exception Safety

Exception safe programming is programming so that if any piece of code that might throw an exception does throw an exception, then the state of the program is not corrupted and resources are not leaked. Getting this right using traditional methods often results in complex, unappealing and brittle code. As a result, exception safety often is either buggy or simply ignored for the sake of expediency.

Example

For example, if there's a Mutex m that must be acquired and held for a few statements, then released:
void abc()
{
    Mutex m = new Mutex;
    lock(m);	// lock the mutex
    foo();	// do processing
    unlock(m);	// unlock the mutex
}

If foo() throws an exception, then abc() exits via exception unwinding, unlock(m) is never called and the Mutex is not released. This is a fatal problem with this code.

The RAII (Resource Acquisition Is Initialization) idiom and the try-finally statement form the backbone of the traditional approaches to writing exception safe programming.

RAII is scoped destruction, and the example can be fixed by providing a Lock class with a destructor that gets called upon the exit of the scope:

class Lock
{
    Mutex m;

    this(Mutex m)
    {
    this.m = m;
    lock(m);
    }

    ~this()
    {
    unlock(m);
    }
}

void abc()
{
    Mutex m = new Mutex;
    scope L = new Lock(m);
    foo();	// do processing
}
If abc() is exited normally or via an exception thrown from foo(), L gets its destructor called and the mutex is unlocked. The try-finally solution to the same problem looks like:
void abc()
{
    Mutex m = new Mutex;
    lock(m);	// lock the mutex
    try
    {
    foo();	// do processing
    }
    finally
    {
    unlock(m);	// unlock the mutex
    }
}

Both solutions work, but both have drawbacks. The RAII solution often requires the creation of an extra dummy class, which is both a lot of lines of code to write and a lot of clutter obscuring the control flow logic. This is worthwhile to manage resources that must be cleaned up and that appear more than once in a program, but it is clutter when it only needs to be done once. The try-finally solution separates the unwinding code from the setup, and it can often be a visually large separation. Closely related code should be grouped together.

The scope exit statement is an easier approach:

void abc()
{
    Mutex m = new Mutex;

    lock(m);	// lock the mutex
    scope(exit) unlock(m);	// unlock on leaving the scope

    foo();	// do processing
}
The scope(exit) statement is executed at the closing curly brace upon normal execution, or when the scope is left due to an exception having been thrown. It places the unwinding code where it aesthetically belongs, next to the creation of the state that needs unwinding. It's far less code to write than either the RAII or try-finally solutions, and doesn't require the creation of dummy classes.

Example

The next example is in a class of problems known as transaction processing:
Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    b = dobar();

    return Transaction(f, b);
}

Both dofoo() and dobar() must succeed, or the transaction has failed. If the transaction failed, the data must be restored to the state where neither dofoo() nor dobar() have happened. To support that, dofoo() has an unwind operation, dofoo_undo(Foo f) which will roll back the creation of a Foo.

With the RAII approach:

class FooX
{
    Foo f;
    bool commit;

    this()
    {
    f = dofoo();
    }

    ~this()
    {
    if (!commit)
        dofoo_undo(f);
    }
}

Transaction abc()
{
    scope f = new FooX();
    Bar b = dobar();
    f.commit = true;
    return Transaction(f.f, b);
}
With the try-finally approach:
Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    try
    {
    b = dobar();
    return Transaction(f, b);
    }
    catch (Object o)
    {
    dofoo_undo(f);
    throw o;
    }
}

These work too, but have the same problems. The RAII approach involves the creation of dummy classes, and the obtuseness of moving some of the logic out of the abc() function. The try-finally approach is wordy even with this simple example; try writing it if there are more than two components of the transaction that must succeed. It scales poorly.

The scope(failure) statement solution looks like:

Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    scope(failure) dofoo_undo(f);

    b = dobar();

    return Transaction(f, b);
}
The dofoo_undo(f) only is executed if the scope is exited via an exception. The unwinding code is minimal and kept aesthetically where it belongs. It scales up in a natural way to more complex transactions:
Transaction abc()
{
    Foo f;
    Bar b;
    Def d;

    f = dofoo();
    scope(failure) dofoo_undo(f);

    b = dobar();
    scope(failure) dobar_unwind(b);

    d = dodef();

    return Transaction(f, b, d);
}

Example

The next example involves temporarily changing the state of some object. Suppose there's a class data member verbose, which controls the emission of messages logging the activity of the class. Inside one of the methods, verbose needs to be turned off because there's a loop that would otherwise cause a blizzard of messages to be output:
class Foo
{
    bool verbose;	// true means print messages, false means silence
    ...
    bar()
    {
    auto verbose_save = verbose;
    verbose = false;
    ... lots of code ...
    verbose = verbose_save;
    }
}
There's a problem if Foo.bar() exits via an exception - the verbose flag state is not restored. That's easily fixed with scope(exit):
class Foo
{
    bool verbose;	// true means print messages, false means silence
    ...
    bar()
    {
    auto verbose_save = verbose;
    verbose = false;
    scope(exit) verbose = verbose_save;

    ...lots of code...
    }
}

It also neatly solves the problem if ...lots of code... goes on at some length, and in the future a maintenance programmer inserts a return statement in it, not realizing that verbose must be reset upon exit. The reset code is where it belongs conceptually, rather than where it gets executed (an analogous case is the continuation expression in a ForStatement). It works whether the scope is exited by a return, break, goto, continue, or exception.

The RAII solution would be to try and capture the false state of verbose as a resource, an abstraction that doesn't make much sense. The try-finally solution requires arbitrarily large separation between the conceptually linked set and reset code, besides requiring the addition of an irrelevant scope.

Example

Here's another example of a multi-step transaction, this time for an email program. Sending an email consists of two operations:
  1. Perform the SMTP send operation.
  2. Copy the email to the “Sent” folder, which in POP is on the local disk, and in IMAP is also remote.

Messages should not appear in “Sent” that haven't been actually sent, and sent messages must actually appear in “Sent”.

Operation (1) is not undoable because it's a well-known distributed computing issue. Operation (2) is undoable with some degree of reliability. So we break the job down into three steps:

  1. Copy the message to “Sent” with a changed title “[Sending] <Subject>”. This operation ensures there's space in the client's IMAP account (or on the local disk), the rights are proper, the connection exists and works, etc.
  2. Send the message via SMTP.
  3. If sending fails, delete the message from “Sent”. If the message succeeds, change its title from “[Sending] <Subject>” to “<Subject>”. Both of these operation have a high probability to succeed. If the folder is local, the probability of success is very high. If the folder is remote, probability is still vastly higher than that of step (1) because it doesn't involve an arbitrarily large data transfer.
class Mailer
{
    void Send(Message msg)
    {
    {
        char[] origTitle = msg.Title();
        scope(exit) msg.SetTitle(origTitle);
        msg.SetTitle("[Sending] " ~ origTitle);
        Copy(msg, "Sent");
    }
    scope(success) SetTitle(msg.ID(), "Sent", msg.Title);
    scope(failure) Remove(msg.ID(), "Sent");
    SmtpSend(msg);	// do the least reliable part last
    }
}
This is a compelling solution to a complex problem. Rewriting it with RAII would require two extra silly classes, MessageTitleSaver and MessageRemover. Rewriting the example with try-finally would require nested try-finally statements or use of an extra variable to track state evolution.

Example

Consider giving feedback to the user about a lengthy operation (mouse changes to an hourglass, window title is red/italicized, ...). With scope(exit) that can be easily done without needing to make an artificial resource out of whatever UI state element used for the cues:
void LongFunction()
{
    State save = UIElement.GetState();
    scope(exit) UIElement.SetState(save);
    ...lots of code...
}
Even more so, scope(success) and scope(failure) can be used to give an indication if the operation succeeded or if an error occurred:
void LongFunction()
{
    State save = UIElement.GetState();
    scope(success) UIElement.SetState(save);
    scope(failure) UIElement.SetState(Failed(save));
    ...lots of code...
}

When to use RAII, try-catch-finally, and Scope

RAII is for managing resources, which is different from managing state or transactions. try-catch is still needed, as scope doesn't catch exceptions. It's try-finally that becomes redundant.

Acknowledgements

Andrei Alexandrescu argued about the usefulness of these constructs on the Usenet and also defined their semantics in terms of try/catch/finally in a series of posts to comp.lang.c++.moderated under the title A safer/better C++? starting Dec 6, 2005. D implements the idea with a slightly modified syntax following its creator's experiments with the feature and useful suggestions from the D programmer community, especially Dawid Ciezarkiewicz and Chris Miller.

I am indebted to Scott Meyers for teaching me about exception safe programming.

References:

  1. Generic<Programming>: Change the Way You Write Exception-Safe Code Forever by Andrei Alexandrescu and Petru Marginean
  2. "Item 29: Strive for exception-safe code" in Effective C++ Third Edition, pg. 127 by Scott Meyers
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Hijack - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Hijack

As software becomes more complex, we become more reliant on module interfaces. An application may import and combine modules from multiple sources, including sources from outside the company. The module developers must be able to maintain and improve those modules without inadvertently stepping on the behavior of modules over which they cannot have knowledge of. The application developer needs to be notified if any module changes would break the application. This talk covers function hijacking, where adding innocent and reasonable declarations in a module can wreak arbitrary havoc on an application program in C++ and Java. We'll then look at how modest language design changes can largely eliminate the problem in the D programming language.

Global Function Hijacking

Let's say we are developing an application that imports two modules: X from the XXX Corporation, and Y from the YYY Corporation. Modules X and Y are unrelated to each other, and are used for completely different purposes. The modules look like:

module X;

void foo();
void foo(long);

module Y;

void bar();

The application program would look like:

import X;
import Y;

void abc()
{
    foo(1);  // calls X.foo(long)
}

void def()
{
    bar();   // calls Y.bar();
}

So far, so good. The application is tested and works, and is shipped. Time goes by, the application programmer moves on, the application is put in maintenance mode. Meanwhile, YYY Corporation, responding to customer requests, adds a type A and a function foo(A):

module Y;

void bar();
class A;
void foo(A);

The application maintainer gets the latest version of Y, recompiles, and no problems. So far, so good. But then, YYY Corporation expands the functionality of foo(A), adding a function foo(int):

module Y;

void bar();
class A;
void foo(A);
void foo(int);

Now, our application maintainer routinely gets the latest version of Y, recompiles, and suddenly his application is doing something unexpected:

import X;
import Y;

void abc()
{
    foo(1);  // calls Y.foo(int) rather than X.foo(long)
}

void def()
{
    bar();   // calls Y.bar();
}

because Y.foo(int) is a better overloading match than X.foo(long). But since X.foo does something completely and totally different than Y.foo, the application now has a potentially very serious bug in it. Even worse, the compiler offers NO indication that this happened and cannot because, at least for C++, this is how the language is supposed to work.

In C++, some mitigation can be done by using namespaces or (hopefully) unique name prefixes within the modules X and Y. This doesn't help the application programmer, however, who probably has no control over X or Y.

The first stab at fixing this problem in the D programming language was to add the rules:

  1. by default functions can only overload against other functions in the same module
  2. if a name is found in more than one scope, in order to use it it must be fully qualified
  3. in order to overload functions from multiple modules together, an alias statement is used to merge the overloads

So now, when YYY Corporation added the foo(int) declaration, the application maintainer now gets a compilation error that foo is defined in both module X and module Y, and has an opportunity to fix it.

This solution worked, but is a little restrictive. After all, there's no way foo(A) would be confused with foo() or foo(long), so why have the compiler complain about it? The solution turned out to be to introduce the notion of overload sets.

Overload Sets

An overload set is formed by a group of functions with the same name declared in the same scope. In the module X example, the functions X.foo() and X.foo(long) form a single overload set. The functions Y.foo(A) and Y.foo(int) form another overload set. Our method for resolving a call to foo becomes:

  1. Perform overload resolution independently on each overload set
  2. If there is no match in any overload set, then error
  3. If there is a match in exactly one overload set, then go with that
  4. If there is a match in more than one overload set, then error

The most important thing about this is that even if there is a BETTER match in one overload set over another overload set, it is still an error. The overload sets must not overlap.

In our example:

void abc()
{
    foo(1);  // matches Y.foo(int) exactly, X.foo(long) with conversions
}

will generate an error, whereas:

void abc()
{
    A a;
    foo(a);  // matches Y.foo(A) exactly, nothing in X matches
    foo();   // matches X.foo() exactly, nothing in Y matches
}

compiles without error, as we'd intuitively expect.

If overloading of foo between X and Y is desired, the following can be done:

import X;
import Y;

alias X.foo foo;
alias Y.foo foo;

void abc()
{
    foo(1);  // calls Y.foo(int) rather than X.foo(long)
}

and no error is generated. The difference here is that the user deliberately combined the overload sets in X and Y, and so presumably both knows what he's doing and is willing to check the foo's when X or Y is updated.

Derived Class Member Function Hijacking

There are more cases of function hijacking. Imagine a class A coming from AAA Corporation:

module M;

class A { }

and in our application code, we derive from A and add a virtual member function foo:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.foo(1);   // calls B.foo(long)
}

and everything is hunky-dory. As before, things go on, AAA Corporation (who cannot know about B) extends A's functionality a bit by adding foo(int):

module M;

class A
{
    void foo(int);
}

Now, consider if we're using Java-style overloading rules, where base class member functions overload right alongside derived class functions. Now, our application call:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.foo(1);   // calls A.foo(int), AAAEEEEEIIIII!!!
}

and the call to B.foo(long) was hijacked by the base class A to call A.foo(int), which likely has no meaning whatsoever in common with B.foo(long). This is why I don't like Java overloading rules. C++ has the right idea here in that functions in a derived class hide all the functions of the same name in a base class, even if the functions in the base class might be a better match. D follows this rule. And once again, if the user desires them to be overloaded against each other, this can be accomplished in C++ with a using declaration, and in D with an analogous alias declaration.

Base Class Member Function Hijacking

I bet you suspected there was more to it than that, and you'd be right. Hijacking can go the other way, too. A derived class can hijack a base class member function!

Consider:

module M;

class A
{
    void def() { }
}

and in our application code, we derive from A and add a virtual member function foo:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.def();   // calls A.def()
}

AAA Corporation once again knows nothing about B, and adds a function foo(long) and uses it to implement some needed new functionality of A:

module M;

class A
{
    void foo(long);

    void def()
    {
        foo(1L);   // expects to call A.foo(long)
    }
}

but, whoops, A.def() now calls B.foo(long). B.foo(long) has hijacked the A.foo(long). So, you might say, the designer of A should have had the foresight for this, and make foo(long) a non-virtual function. The problem is that A's designer may very easily have intended A.foo(long) to be virtual, as it's a new feature of A. He cannot have known about B.foo(long). Take this to the logical conclusion, and we realize that under this system of overriding, there is no safe way to add any functionality to A.

The D solution is straightforward. If a function in a derived class overrides a function in a base class, it must use the storage class override. If it overrides without using the override storage class it's an error. If it uses the override storage class without overriding anything, it's an error.

class C
{
    void foo();
    void bar();
}
class D : C
{
    override void foo();  // ok
    void bar();           // error, overrides C.bar()
    override void abc();  // error, no C.abc()
}

This eliminates the potential of a derived class member function hijacking a base class member function.

Derived Class Member Function Hijacking #2

There's one last case of base member function hijacking a derived member function. Consider:

module A;

class A
{
    void def()
    {
        foo(1);
    }

    void foo(long);
}

Here, foo(long) is a virtual function that provides a specific functionality. Our derived class designer overrides foo(long) to replace that behavior with one suited to the derived class' purpose:

import A;

class B : A
{
    override void foo(long);
}

void abc(B b)
{
    b.def();   // eventually calls B.foo(long)
}

So far, so good. The call to foo(1) inside A winds up correctly calling B.foo(long). Now A's designer decides to optimize things, and adds an overload for foo:

module A;

class A
{
    void def()
    {
    foo(1);
    }

    void foo(long);
    void foo(int);
}

Now,

import A;

class B : A
{
    override void foo(long);
}

void abc(B b)
{
    b.def();   // eventually calls A.foo(int)
}

Doh! B thought he was overriding the behavior of A's foo, but did not. B's programmer needs to add another function to B:

class B : A
{
    override void foo(long);
    override void foo(int);
}

to restore correct behavior. But there's no clue he needs to do that. Compile time is of no help at all, as the compilation of A has no knowledge of what B overrides.

Let's look at how A calls the virtual functions, which it does through the vtbl[]. A's vtbl[] looks like:

A.vtbl[0] = &A.foo(long);
A.vtbl[1] = &A.foo(int);

B's vtbl[] looks like:

B.vtbl[0] = &B.foo(long);
B.vtbl[1] = &A.foo(int);

and the call in A.def() to foo(int) is actually a call to vtbl[1]. We'd really like A.foo(int) to be inaccessible from a B object. The solution is to rewrite B's vtbl[] as:

B.vtbl[0] = &B.foo(long);
B.vtbl[1] = &error;

where, at runtime, an error function is called which will throw an exception. It isn't perfect since it isn't caught at compile time, but at least the application program won't blithely be calling the wrong function and continue on.

Update: A compile time warning is now generated whenever the vtbl[] gets an error entry.

Conclusion

Function hijacking is a pernicious and particularly nasty problem in complex C++ and Java programs because there is no defense against it for the application programmer. Some small modifications to the language semantics can defend against it without sacrificing any power or performance.

References

  • digitalmars.D - Hijacking
  • digitalmars.D - Re: Hijacking
  • digitalmars.D - aliasing base methods
  • Eiffel, Scala and C# use override or something analogous

Credits:

  • Kris Bell
  • Frank Benoit
  • Andrei Alexandrescu
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Introduction to std.datetime - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Introduction to std.datetime

by Jonathan M Davis

Introduction

In dmd 2.052, the module std.datetime was introduced. It will be replacing std.date entirely. As such, std.date is currently scheduled for deprecation. At a later date it will be deprecated (at which point, you'll have to compile with -d for it to work rather than simply having the compiler complain when you use it), and eventually it will be fully removed from Phobos. What this means is that all new code should be written to use std.datetime and that any code which currently uses std.date is going to need to be refactored to use std.datetime (unless you want to copy std.date to your own code and continue to use it as a non-Phobos module). This article attempts to familiarize you with std.datetime as well as give some advice on how to migrate code from std.date to std.datetime for those who have been using std.date.

std.date is essentially a C-based solution for dates and times. It uses d_time to hold time where d_time is a 64-bit integral value holding the number of milliseconds which have passed since midnight, January 1st, 1970 A.D. in UTC. C, on the other hand, uses time_t to hold time where time_t is an integral value holding the number of seconds which have passed since midnight, January 1st, 1970 A.D. in UTC. Its size varies from architecture to architecture (typically 32 bits on a 32-bit machine and 64 bits on a 64-bit machine, but it varies with the OS and compiler). The exact set of functions that std.date provides for using with d_time aren't the same as what C provides for using with time_t, but their representation of time is virtually the same.

std.datetime, on the other hand, is very much an object-oriented solution, and it's not C-based at all. Rather, its API is based on Boost's types for handling dates and times (though they're far from identical). So, it's a bit of a paradigm shift to move from std.date to std.datetime. Don't expect much to be the same between the two. However, std.datetime is not plagued with the same bugs that std.date is plagued with (std.date being quite buggy in general), and it provides much more functionality than std.date does. So, in the long run at least, dealing with std.datetime should be much more pleasant - though migration is likely to present a bit of a hurdle in the short term.

Basic Concepts of std.datetime

Most things in std.datetime are based on and/or use three concepts:

  • Duration: A duration of time with units. e.g. 4 days or 72 seconds.
  • Time Point: A specific point in time. e.g. 21:00 or May 7th, 2013.
  • Time Interval: A fixed period of time. e.g. [02:44 - 12:22) or [February 4th, 1922 - January 17th, 1955).

Durations

The duration types can actually be found in core.time. They are Duration and TickDuration. TickDuration is intended for precision timing and is used primarily with StopWatch and the benchmarking functions found in std.datetime - such as benchmark - and you're unlikely to use it outside of using them. Duration, on the other hand, you're likely to use quite a bit.

Duration holds its time internally as hecto-nanoseconds (100 ns), so that's its maximum precision. It has property functions for both returning the duration of time truncated to a particular unit (such as the days and seconds property functions) as well as a function for returning the total number of a particular unit in that Duration (the total function).

Generally, a Duration is created in one of two ways: by subtracting two time points or with the core.time.dur function. So, for instance, if you subtracted a time point which represented 17:02 from a time point which represented 6:07, you'd get a Duration which represented 10 hours and 55 minutes. Or, if you wanted to create a Duration directly, then you'd use the dur function and make a call like dur!"hours"(17) or dur!"seconds"(234).

auto duration = TimeOfDay(17, 2) - TimeOfDay(6, 7);
assert(duration == dur!"hours"(10) + dur!"minutes"(55));
assert(duration.hours == 10);
assert(duration.minutes == 55);
assert(duration.total!"hours"() == 10);
assert(duration.total!"minutes"() == 655);
assert(duration.total!"hnsecs"() == 393_000_000_000);

Like any number, Durations can be added together or subtracted from. However, unlike a naked number, they have units associated with them and will handle the appropriate conversions. Also, it should be noted that the various functions in druntime and Phobos which take a duration of time take an actual Duration rather than a naked number (most currently take both, though the versions which take a naked number are going to be deprecated). For instance, core.thread.sleep takes a Duration, as does std.concurrency.receiveTimeout. So, durations are used outside of just interacting with core.time and std.datetime.

One particular thing to note here is how both dur and total take a string representing the units of time to be used. This is an idiom used throughout core.time and std.datetime. The possible units are "years", "months", "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", and "nsecs". It should be noted however that very few functions take "nsecs", because nothing in std.datetime, and very little in core.time, has precision greater than hnsecs (100 ns). Also, a number of functions (such as core.time.dur) do not take "years" or "months", because it is not possible to convert between years or months and smaller units without a specific date. So, while you can add a Duration to a time point, if you want to add years or months to one, you must use a separate function (such as add) to do that - and those will take "years" and "months".

Time Points

std.datetime has 4 types which represent time points.

  • Date
  • TimeOfDay
  • DateTime
  • SysTime

A Date represents a date and holds its year, month, and day as separate values internally. A TimeOfDay represents a time of day, 00:00:00 - 23:59:59, and holds its hour, minute, and second as separate values internally. A DateTime represents a date and time and holds its values as a Date and TimeOfDay internally. None of these types have any concept of time zone. They represent generic dates and/or times and are best-suited for cases where you need a date and/or time but don't care about time zone. Also, because they hold their values separated internally, those values don't have to be calculated every time that you ask for them.

auto date = Date(1992, 12, 27);
auto tod = TimeOfDay(7, 0, 22);
auto dateTime = DateTime(1992, 12, 27, 7, 0, 22);
assert(date == dateTime.date);
assert(tod == dateTime.timeOfDay);

A SysTime, however, is an entirely different beast. It represents a date and time - similar to DateTime - but it goes to hnsec precision instead of only second precision, and it incorporates the concept of time zone. Its time is held internally as a 64-bit integral value which holds the number of hnsecs which have passed since midnight, January 1st, 1 A.D. in UTC. It also has a TimeZone object which it uses to polymorphically adjust its UTC value to the appropriate time zone when querying for values such as its year or hour.

SysTime is the type which is used to interface with the system's clock. When you ask for the current time, you get a SysTime. And because it always holds its internal value in UTC, it never has problems with DST or time zone changes. It has most of the functions that DateTime has as well as a number of functions specific to it. It can be cast to the other 3 time point types as well as be constructed from them, but you do risk problems with DST when creating a SysTime from the other 3 time points unless you specifically create the SysTime with a TimeZone which doesn't have DST (such as std.datetime.UTC), since when a time zone has DST, one hour of the year does not exist, and another exists twice. You can also convert to and from unix time, which is what you're dealing with in C with time_t.

The one other related type which I should mention at this point is core.time.FracSec. It holds fractional seconds, and it is what you get from a Duration or SysTime when you specifically ask for the fractional portion of the time.

auto st1 = Clock.currTime(); //Current time in local time.
auto st2 = Clock.currTime(UTC()); //Current time in UTC.
auto st3 = SysTime(DateTime(1992, 12, 27, 7, 0, 22), FracSec.from!"usecs"(5));
assert((cast(Date)st3) == Date(1992, 12, 27));
assert((cast(TimeOfDay)st3) == TimeOfDay(7, 0, 22));
assert((cast(DateTime)st3) == DateTime(1992, 12, 27, 7, 0, 22));
assert(st3.fracSec == FracSec.from!"hnsecs"(50));

Time Intervals

std.date has nothing to correspond to time intervals, so I won't go over them in great detail. Essentially, they're constructed from either two time points or a time point and a duration. Interval is a finite time interval with two end points, whereas PosInfInterval is an infinite time interval starting at a specific time point and going to positive infinity, and NegInfInterval is an infinite time interval starting at negative infinity and going to a specific time point. They have various operations for dealing with intersections and the like. It is also possible to create ranges over them if you want to operate on a range of time points. Take a look at the documentation for more details.

Interfacing with C

Hopefully, you can do everything that you need to do using the types in core.time and std.datetime, but if you do need to interface with C code, then you can. C's time_t uses "unix time" (seconds since midnight, January 1st, 1970 A.D. in UTC), whereas SysTime uses what it calls "std time" (hnsecs since midnight January 1st, 1 A.D. in UTC). Translating between the two is fairly straightforward. To get a time_t from a SysTime, simply call toUnixTime on the SysTime. To convert the other way around, you first need to convert a time_t to std time, then pass that value to SysTime's constructor. And if you ever simply need a SysTime's std time for any reason, then use its stdTime property.

time_t unixTime = core.stdc.time.time(null);
auto stdTime = unixTimeToStdTime(unixTime);
auto st = SysTime(stdTime);
assert(unixTime == st.toUnixTime());
assert(stdTime == st.stdTime);

Hecto-nanoseconds were chosen as the internal representation of Duration and SysTime, because that is the highest precision that you can use with a 64-bit integer and still cover a reasonable amount of time (SysTime covers from around 29,000 B.C. to around 29,000 A.D.). It also happens to be the same internal representation that C# uses, so if you need to interface with C# for any reason, converting between its representation of time and std.datetime's representation is extremely easy, since no conversion is necessary. C#'s DateTime uses both the same units and epoch for its internal representation (which it calls Ticks) as SysTime, though unlike SysTime, it doesn't work with negative values (which would be B.C.) and doesn't go past the end of 9,999 A.D. Most programs are unlikely to care about values outside that range however. Regardless, hnsecs make the most sense for std.datetime, which tries to have the highest precision that it reasonably can, so that's why they were picked.

Recommendations on Using std.datetime

Whether Date, TimeOfDay, DateTime, or SysTime is more appropriate in a particular situation depends very much on that situation. Date, TimeOfDay, and DateTime generally make the most sense when you're dealing with generic dates and times that have nothing to do with time zones, but if you're dealing with time zones at all or are dealing with anything which needs to worry about DST, you should use SysTime. Because it keeps its time internally in UTC, it avoids problems with DST. And while it does have a time zone component, it defaults to std.datetime.LocalTime (which is the time zone type for the local time of the system), so you don't generally have to deal directly with time zones if you don't want to.

If you do want to deal with time zones, then the time zone types in std.datetime are LocalTime, UTC, SimpleTimeZone, PosixTimeZone, and WindowsTimeZone - or if for some reason, they don't do what you need, you can always create your own time zone class derived from TimeZone. That's unlikely to be necessary, however (and if you think that you have come up with such a class which would be generally useful, please bring it up in the digitalmars.D newsgroup, since if it's truly generally useful, we may want some version of it in std.datetime). Read their documentation for more details. Most applications shouldn't have to worry about time zones though, beyond perhaps using UTC instead of LocalTime in some cases.

When it comes to saving a time point to disk or a database or something similar, I would generally recommend using the toISOString or toISOExtString functions, since both are standard ISO formats for date-time strings (toISOExtString is likely better in the general case, since it's more humanly readable, but they're both standard). You can then use fromISOString or fromISOExtString to recreate the appropriate time type later. toString uses the toSimpleString function, which is an invention of Boost and is somewhat more humanly readable, but it isn't standard, so you probably shouldn't use it for saving time point values.

auto dateTime = DateTime(1997, 5, 4, 12, 22, 3);
assert(dateTime.toISOString() == "19970504T122203");
assert(dateTime.toISOExtString() == "1997-05-04T12:22:03");
assert(dateTime.toSimpleString() == "1997-May-04 12:22:03");
auto restored = DateTime.fromISOExtString(dateTime.toISOExtString());
assert(dateTime == restored);

One area with saving times as strings which gets a bit awkward is time zones. The time zone is included in the string as part of the ISO standard, but all it contains is the total offset from UTC at that particular date and time, so you can't generally use an ISO string (extended or otherwise) to get the exact time zone which the SysTime originally had. Rather, it will be restored with a SimpleTimeZone with the given offset from UTC (except in the case of UTC, where it can restore UTC). On the other hand, if you're using LocalTime, then the time zone is not part of the string (per the ISO standard), and restoring the SysTime will restore it to whatever the current time zone is on the box, regardless of what the original time zone was. However, because in all cases, except for LocalTime, the UTC offset is included in the string, it is generally possible to get the exact UTC time that the SysTime was for. But you can't usually restore the original time zone from just the ISO string.

auto local = SysTime(629_983_705_230_000_035);
auto utc = local.toUTC();
auto other = local.toOtherTZ(TimeZone.getTimeZone("America/New_York"));

//This assumes that you're in "America/Los_Angeles". You'd get a different
//time if you're in a different time zone.
assert(local.toISOExtString() == "1997-05-04T12:22:03.0000035");

assert(utc.toISOExtString() == "1997-05-04T19:22:03.0000035Z");
assert(other.toISOExtString() == "1997-05-04T15:22:03.0000035-04:00");

auto restLocal = SysTime.fromISOExtString(local.toISOExtString());
auto restUTC = SysTime.fromISOExtString(utc.toISOExtString());
auto restOther = SysTime.fromISOExtString(other.toISOExtString());

//Only guaranteed because it's on the same machine.
assert(restLocal == local);

//Guaranteed regardless of machine. Their internal values could differ however.
assert(cast(DateTime)restLocal == cast(DateTime)local);

//Time zone is UTC for both.
assert(restUTC == utc);

//Time zone for restOther is SimpleTimeZone(-4 * 60), not "America/New_York".
assert(restOther == other);

To summarize, UTC and SimpleTimeZone can be restored exactly using an ISO or ISO extended string. However, none of the other TimeZones can be. LocalTime is restored with the same date and time but in the local time zone of the computer it's restored on, so its std time may differ. Other time zones end up with the restored SysTime having the same std time as the original, but the new time zone is a SimpleTimeZone with the same total UTC offset which the original time zone had at the given std time, but you don't get the original time zone back. That works just fine if you don't ever need to change the value of that SysTime or need to know the name of the original time zone, but it is inadequate if you need to do either of those, since the rules for the new time zone won't match those of the original.

So, if you don't care about the time zone or if the restored SysTime has the same std time as the original, then LocalTime is fine. However, if you want the std time to be consistent, then avoid LocalTime. In most cases, I'd advise simply using UTC as the time zone when saving the time. And if you want to restore the time zone such that it's the same time zone with the same rules as it was prior to saving the time, then you're going to need to save that information yourself. With a PosixTimeZone or a WindowsTimeZone, all you have to do is save the time zone's name (which for them is the TZ database name and the Windows time zone name of that time zone respectively). That can be used to restore the time zone. If it's a SimpleTimeZone or UTC, then you don't have to do anything, because the ISO string will be enough. If you're using LocalTime, however, you're in a bit of a bind.

The restored time zone will be LocalTime, so if you want it to be whatever the local time of the computer you're doing the restoring on is, then you're fine. But if you want to be able to have the same actual time zone restored regardless of the local time of the computer restoring the time, you'll need to figure out what the time zone's TZ database name or Windows time zone name is on the original computer so that you can use it to get its corresponding PosixTimeZone or WindowsTimeZone on the computer that's doing the restoring. But it's actually really hard to accurately determine the TZ database name or Windows time zone name of the local time zone on any OS other than on Windows, so std.datetime doesn't currently provide a way to do that. I expect that such a requirement would be quite rare however. In most cases, you'll care about LocalTime and/or UTC, and even if you're using PosixTimeZone or WindowsTimeZone, odds are that restoring the time with the correct std time value and correct UTC offset will be enough (and if it's not, you can always save the time zone's name to restore the correct PosixTimeZone or WindowsTimeZone). It's just LocalTime that has the problem. However, if a function to accurately determine the TZ database name of the local time zone on Posix systems is ever devised, then it will be added to std.datetime.

The other, more compact, option for saving a SysTime is to just save its std time as a 64-bit integer. It's not really humanly readable like an ISO or ISO extended string would be, but it takes up less space if saved as an actual number rather than a string. However, you do then have to worry about the time zone yourself entirely if you wish to be able to restore it. But if you save the current UTC offset (meaning the UTC offset with the DST offset applied - such as an ISO string would include), that would be enough to correctly give what the time would have been in the original time zone even if you can't restore that time zone.

Well, that's probably more than enough on time zones. In most cases, you shouldn't need to care about them (SysTime is designed to make it so that you shouldn't have to worry about them if you don't want to), but std.datetime strives to give the best tools possible for handling time zones when you actually want to. Regardless, by far the biggest gain that SysTime gives you is that its internal time is always in UTC, so regardless of whether you try and do anything with time zones explicitly, you won't have any problems with DST changes when dealing with SysTime.

One last suggestion on using SysTime would be that if you need to query it for more than one of its properties (e.g. day or hour), or if you need to do it many times in a row, and the SysTime isn't going to change, then you should probably cast it to another time point type (probably DateTime) and query it for those values. The reason for this is that every time that you call a property function on a SysTime, it has to convert its internal std time to the value of the property that you're asking for, whereas if you convert it to a DateTime, the DateTime holds those values separately, and you only have to do the calculations once - when you do the conversion from the SysTime to a DateTime. If what you're doing doesn't need that extra boost of efficiency, then you might as well not bother, but it is good to be aware that it's less efficient to query each of SysTime's properties individually rather than converting it to a DateTime and then querying it.

auto st = Clock.currTime();

//Each value must be individually calculated.
{
    auto year = st.year;
    auto month = st.month;
    auto day = st.day;
    auto hour = st.hour;
    auto minute = st.minute;
    auto second = st.second;
    auto fracSec = st.fracSec;
}

/+
    You do the calculations only twice if you convert to a DateTime
    (twice instead of once, because you're still asking for FracSec
    separately, though that particular calculation is fairly cheap).
 +/
auto dateTime = cast(DateTime)st;
{
    auto year = dateTime.year;
    auto month = dateTime.month;
    auto day = dateTime.day;
    auto hour = dateTime.hour;
    auto minute = dateTime.minute;
    auto second = dateTime.second;
    auto fracSec = st.fracSec;
}

Migrating to std.datetime

Okay, hopefully you have a fair idea of the basics of std.datetime at this point (though there's plenty more which is covered in the documentation), but the big question for many is how best to handle converting your code from using std.date to using std.datetime. When using std.date, you would have been using d_time, and if you had to worry about time zones, you were probably either using C functions to deal with conversions or just doing them yourself, since the functionality in std.date which relates to time zones is rather broken. As a result, most of what you would have done would likely be in UTC.

SysTime holds its time internally in UTC in a manner similar to d_time (albeit with different units and a different epoch), and it is the type intended for dealing with the time from the system's clock, so SysTime is generally what d_time should be replaced with. Functions in Phobos which previously took or returned a d_time now take or return a SysTime or are scheduled to be deprecated and have replacement functions which take or return a SysTime. Generally, in the case where a function took a d_time, that function is now overloaded with a version which takes a SysTime, but in cases where a function could not be overloaded (such as when it simply returned a d_time), a new function has been added to replace the old one (so as to avoid breaking existing code). The module that this impacts the most is std.file. For example,

d_time dTime = "myfile.txt".lastModified();
SysTime sysTime = "myfile.txt".timeLastModified();

setTimes("yourfile.txt", dTime, dTime + 5);
setTimes("yourfile.txt", sysTime, sysTime + dur!"msecs"(5));

With all such functions, it's simply a matter of changing the type of the argument that you're passing to the function or assigning its return value to and possibly changing the function name that you're calling so that it's the version that returns a SysTime. Those changes are quite straightforward and not particularly disruptive. Of greater concern are the formats that times are printed or saved in and how time zones are dealt with.

If you were saving the integral d_time value anywhere, then you're either going to have to switch to saving a value that SysTime would use as discussed previously (such as its std time or its ISO string), or you're going to have be converting between d_time and SysTime. At present, the functions std.datetime.sysTimeToDTime and std.datetime.dTimeToSysTime will do those conversions for you. So, converting between the two formats is easy. However, because d_time is going away, those functions will be going away. That means that you either need to refactor your code so that those functions aren't necessary, or you need to copy them to your own code to continue to use them.

As for formatted strings, std.datetime currently only supports ISO strings, ISO extended strings, and Boost's simple string. Eventually, it should have functions for custom strings, but a well-designed function for creating custom strings based on format strings is not easy to design, and it hasn't been done for std.datetime yet (it's on my todo list, but it could be a while before I get to it). So, in general, you're either going to have to switch to using one of the string formats that std.datetime supports, or you're going to have to generate and parse the string format that you want yourself. In some cases, you should be able to adjust the string that core.stdc.time.ctime gives you, and in others, you may be able to use toISOExtString and adjust what it gives you, but there's a decent chance that you're going to have to just create and parse the strings yourself using the various properties on SysTime. One major difference between the string functions in std.date and those in std.datetime to note is that unlike std.date, aside from Boost's simple strings, nothing in std.datetime prints the names of months or weekdays, because that poses a localization issue. So, unless you're using core.stdc.time.ctime to get those values, you're going to have to create the names yourself.

Now, if you were doing anything with time zones with std.date, odds are that you were doing all of those conversions yourself (since that's one of the areas where std.date is buggy). That being the case, you probably have the offset from UTC and the offset adjustment for DST for whatever time zone you're dealing with. What is likely the best way to handle that is to create a SimpleTimeZone using those values. Simply calculate the total UTC offset (so add in the DST offset if it applies for the date in question) in minutes and create a SimpleTimeZone with that. Note that std.datetime treats west of UTC as negative (for some reason, some systems - particularly Posix stuff - use a positive offset from UTC when west of UTC, in spite of the fact that when talking about time zones, negative is always used for west of UTC, and that's what the ISO standard strings do). So, you may have to adjust your values accordingly. Regardless, be very careful to make sure that you understand what the values you've been using represent in units of time and whether you need to be adding or subtracting them to convert them to what SimpleTimeZone expects for its offset from UTC: the minutes to add to the time in UTC to get the time in the target time zone.

//These are the same offsets as America/Los_Angeles.
auto utcOffset = -8 * 60;
auto dstOffset = 60;

immutable tzWithDST = new SimpleTimeZone(utcOffset + dstOffset);
immutable tzWithoutDST = new SimpleTimeZone(utcOffset);

The last thing that I have to note is some differences in numerical values between std.date and std.datetime. std.date.Date's weekday property gives Sunday a value of 1, but std.date.weekDay gives Sunday a value of 0. std.datetime.DayOfWeek gives Sunday a value of 0. So, depending on which part of std.date you're dealing with it, it may or may not match what std.datetime is doing for the numerical values of weekdays. Months have a similar problem. std.date.Date's month property gives January a value of 1 - which matches what std.datetime.Month does - but std.date.monthFromTime gives January a value of 0. So, just as with the days of the week, you have to be careful with the numerical values of the months. Whether std.datetime matches what std.date is doing depends on which part of std.date you're using. And as you'll notice, it's not even consistent as to whether std.date.Date or the free function in std.date is the one which matches std.datetime. So, you should be very careful when converting code which uses numerical values for either the days of the week or the months of the year.

std.date symbols and their std.datetime counterparts
std.date | std.datetime Equivalent
d_time | The closest would be SysTime.
d_time_nan | There is no equivalent. SysTime.init, which has a null TimeZone object, would be the closest, but once CTFE advances to the point that you can new up class objects with it, SysTime.init's timezone will be LocalTime, so don't rely on SysTime.init being invalid. std.datetime in general tries to avoid having any invalid states for any of its types. It's intended that creating such values be impossible.
Date SysTime
Date.year | SysTime.year
Date.month | SysTime.month
Date.day | SysTime.day
Date.hour | SysTime.hour
Date.minute | SysTime.minute
Date.second | SysTime.second
Date.ms | SysTime.fracSec.msecs
Date.weekday | SysTime.dayOfWeek - but note that the values are off by 1.
Date.tzcorrection
immutable tz = sysTime.timezone;
auto diff = tz.utcToTZ(sysTime.stdTime) - sysTime.stdTime;
auto tzcorrection = convert!("hnsecs", "minutes")(diff);
However, it looks like tzcorrection is broken, so you're probably not using it in your code anyway.
Date.parse | SysTime.fromISOString, SysTime.fromISOExtString, and SysTime.fromSimpleString, but the formats of the strings differ from what std.date.Date.parse accepts.
ticksPerSecond | There is no equivalent. It's only relevant to d_time.
toISO8601YearWeek | SysTime.isoWeek
hourFromTime | SysTime.hour
minFromTime | SysTime.minute
secFromTime | SysTime.second
daysInYear | sysTime.isLeapYear ? 366 : 365
dayFromYear | (sysTime - SysTime(Date(1970, 1, 1), UTC())).total!"days"()
yearFromTime | SysTime.year
inLeapYear | SysTime.isLeapYear
monthFromTime | SysTime.month - but note that the values are off by 1.
dateFromTime | SysTime.day
weekDay | SysTime.dayOfWeek
UTCtoLocalTime | SysTime.toUTC
dateFromNthWeekdayOfMonth
//There is no equivalent. This is a possible implementation.
int dateFromNthWeekdayOfMonth(int year, Month month,
                              DayOfWeek dow, int n)
{
    auto first = Date(year, month, 1);
    auto target = first;
    immutable targetDOTW = target.dayOfWeek;

    if(targetDOTW != dow)
    {
        if(targetDOTW < dow)
            target += dur!"days"(dow - targetDOTW);
        else
        {
            target += dur!"days"((DayOfWeek.sat - targetDOTW) +
                                 dow + 1);
        }
    }

    target += dur!"weeks"(n - 1);

    if(target.month != first.month)
        target -= dur!"weeks"(1);

    return cast(int)((target - first).total!"days"()) + 1;
}
daysInMonth | SysTime.endOfMonthDay; Actually, this name is overly easy to confuse with endOfMonth - which returns a SysTime of the last day of the month. I will probably rename this to daysInMonth. But if I do, it won't be until the next release (2.054), and this name will be around until it's gone through the full deprecation cycle.
UTCtoString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
toUTCString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though.
toDateString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
toTimeString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
parse.parse | SysTime.fromISOString, SysTime.fromISOExtString, and SysTime.fromSimpleString, but the formats of the strings differ from what std.date.parse accepts.
getUTCtime | Clock.currTime(UTC()) if you want the SysTime to have its time zone be UTC. More likely though, you'll just use Clock.currTime(). Its internal time is in UTC regardless.
DosFileTime DosFileTime
toDtime DosFileTimeToSysTime
toDosFileTime SysTimeToDosFileTime
benchmark benchmark

Note that I'm not an expert on what does and doesn't work in std.date, so while I have noted some of the functions that I know to be broken, just because a function isn't labeled as broken in the above table does not mean that it works correctly. And any function which doesn't work correctly is obviously not going to give the same results as the std.datetime equivalent, since it's almost certain that the std.datetime version isn't buggy, let alone buggy in the same way (if it is buggy, the bug is almost certainly going to be far more subtle than any bug in std.date, since std.datetime is quite thoroughly unit tested).

Conclusion

Hopefully this article has improved your understanding of std.datetime and will get you well on your way to being able to migrate your code from std.date to std.datetime. If you have any further questions, please ask them on the digitalmars.D.learn newsgroup. And if there's a major use case of std.date which is not easy to convert over to std.datetime which I missed in this article and you think should be in it, please feel free to bring it up on the digitalmars.D newsgroup, and if need be, I'll update this article with the relevant information.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on DateTime


LazyEvaluationOfFunctionArguments - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

LazyEvaluationOfFunctionArguments

by Walter Bright, http://www.digitalmars.com/d

Lazy evaluation is the technique of not evaluating an expression unless and until the result of the expression is required. The &&, || and ?: operators are the conventional way to do lazy evaluation:

void test(int* p)
{
    if (p && p[0])
    ...
}

The second expression p[0] is not evaluated unless p is not null. If the second expression was not lazily evaluated, it would generate a runtime fault if p was null.

While invaluable, the lazy evaluation operators have significant limitations. Consider a logging function, which logs a message, and can be turned on and off at runtime based on a global value:

void log(char[] message)
{
    if (logging)
    fwritefln(logfile, message);
}

Often, the message string will be constructed at runtime:

void foo(int i)
{
    log("Entering foo() with i set to " ~ toString(i));
}

While this works, the problem is that the building of the message string happens regardless of whether logging is enabled or not. With applications that make heavy use of logging, this can become a terrible drain on performance.

One way to fix it is by using lazy evaluation:

void foo(int i)
{
    if (logging) log("Entering foo() with i set to " ~ toString(i));
}

but this violates encapsulation principles by exposing the details of logging to the user. In C, this problem is often worked around by using a macro:

#define LOG(string)  (logging && log(string))

but that just papers over the problem. Preprocessor macros have well known shortcomings:

  • The logging variable is exposed in the user's namespace.
  • Macros are invisible to symbolic debuggers.
  • Macros are global only, and cannot be scoped.
  • Macros cannot be class members.
  • Macros cannot have their address taken, so cannot be passed indirectly like functions can.

A robust solution would be a way to do lazy evaluation of function parameters. Such a way is possible in the D programming language using a delegate parameter:

void log(char[] delegate() dg)
{
    if (logging)
    fwritefln(logfile, dg());
}

void foo(int i)
{
    log( { return "Entering foo() with i set to " ~ toString(i); });
}

Now, the string building expression only gets evaluated if logging is true, and encapsulation is maintained. The only trouble is that few are going to want to wrap expressions with { return exp; }.

So D takes it one small, but crucial, step further (suggested by Andrei Alexandrescu). Any expression can be implicitly converted to a delegate that returns either void or the type of the expression. The delegate declaration is replaced by the lazy storage class (suggested by Tomasz Stachowiak). The functions then become:

void log(lazy char[] dg)
{
    if (logging)
    fwritefln(logfile, dg());
}

void foo(int i)
{
    log("Entering foo() with i set to " ~ toString(i));
}

which is our original version, except that now the string is not constructed unless logging is turned on.

Any time there is a repeating pattern seen in code, being able to abstract out that pattern and encapsulate it means we can reduce the complexity of the code, and hence bugs. The most common example of this is the function itself. Lazy evaluation enables encapsulation of a host of other patterns.

For a simple example, suppose an expression is to be evaluated count times. The pattern is:

for (int i = 0; i < count; i++)
   exp;

This pattern can be encapsulated in a function using lazy evaluation:

void dotimes(int count, lazy void exp)
{
    for (int i = 0; i < count; i++)
       exp();
}

It can be used like:

void foo()
{
    int x = 0;
    dotimes(10, writef(x++));
}

which will print:

0123456789

More complex user defined control structures are possible. Here's a method to create a switch like structure:

bool scase(bool b, lazy void dg)
{
    if (b)
    dg();
    return b;
}

/* Here the variadic arguments are converted to delegates in this
   special case.
 */
void cond(bool delegate()[] cases ...)
{
    foreach (c; cases)
    {	if (c())
        break;
    }
}

which can be used like:

void foo()
{
    int v = 2;
    cond
    (
    scase(v == 1, writefln("it is 1")),
    scase(v == 2, writefln("it is 2")),
    scase(v == 3, writefln("it is 3")),
    scase(true,   writefln("it is the default"))
    );
}

which will print:

it is 2

Those familiar with the Lisp programming language will notice some intriguing parallels with Lisp macros.

For a last example, there is the common pattern:

Abc p;
p = foo();
if (!p)
    throw new Exception("foo() failed");
p.bar();	// now use p

Because throw is a statement, not an expression, expressions that need to do this need to be broken up into multiple statements, and extra variables are introduced. (For a thorough treatment of this issue, see Andrei Alexandrescu and Petru Marginean's paper Enforcements). With lazy evaluation, this can all be encapsulated into a single function:

Abc Enforce(Abc p, lazy char[] msg)
{
    if (!p)
    throw new Exception(msg());
    return p;
}

and the opening example above becomes simply:

Enforce(foo(), "foo() failed").bar();

and 5 lines of code become one. Enforce can be improved by making it a template function:

T Enforce(T)(T p,  lazy char[] msg)
{
    if (!p)
    throw new Exception(msg());
    return p;
}

Conclusion

Lazy evaluation of function arguments dramatically extends the expressive power of functions. It enables the encapsulation into functions of many common coding patterns and idioms that previously were too clumsy or impractical to do.

Acknowledgements

I gratefully acknowledge the inspiration and assistance of Andrei Alexandrescu, Bartosz Milewski, and David Held. The D community helped a lot with much constructive criticism, such as the thread starting with Tomasz Stachowiak in D/41633.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Memory Management - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Memory Management

Most non-trivial programs needs to allocate and free memory. Memory management techniques become more and more important as programs increase in complexity, size, and performance. D offers many options for managing memory.

The three primary methods for allocating memory in D are:

  1. Static data, allocated in the default data segment.
  2. Stack data, allocated on the CPU program stack.
  3. Garbage collected data, allocated dynamically on the garbage collection heap.

The techniques for using them, as well as some advanced alternatives are:

  • Strings (and Array) Copy-on-Write
  • Real Time
  • Smooth Operation
  • Free Lists
  • Reference Counting
  • Explicit Class Instance Allocation
  • Mark/Release
  • RAII (Resource Acquisition Is Initialization)
  • Allocating Class Instances On The Stack
  • Allocating Uninitialized Arrays On The Stack
  • Interrupt Service Routines

Strings (and Array) Copy-on-Write

Consider the case of passing an array to a function, possibly modifying the contents of the array, and returning the modified array. As the contents of an array are accessed through a reference, a crucial issue is who owns the contents of the array? For example, a function to convert an array of characters to upper case:

char[] toupper(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 - ('a' - 'A'));
    }
    return s;
}

Note that the caller's version of s[] is also modified. This may be not at all what was intended, or worse, s[] may be a slice into a read-only section of memory.

If a copy of s[] was always made by toupper(), then that will unnecessarily consume time and memory for strings that are already all upper case.

The solution is to implement copy-on-write, which means that a copy is made only if the string needs to be modified. Some string processing languages do do this as the default behavior, but there is a huge cost to it. The string "abcdeF" will wind up being copied 5 times by the function. To get the maximum efficiency using the protocol, it'll have to be done explicitly in the code. Here's toupper() rewritten to implement copy-on-write in an efficient manner:

char[] toupper(char[] s)
{
    int changed;
    int i;

    changed = 0;
    for (i = 0; i < s.length; i++)
    {
        char c = s[i];
        if ('a' <= c && c <= 'z')
        {
            if (!changed)
            {
                char[] r = new char[s.length];
                r[] = s;
                s = r;
                changed = 1;
            }
            s[i] = cast(char)(c - ('a' - 'A'));
        }
    }
    return s;
}

Copy-on-write is the protocol implemented by array processing functions in the D Phobos runtime library.

Real Time

Real time programming means that a program must be able to guarantee a maximum latency, or time to complete an operation. With most memory allocation schemes, including malloc/free and garbage collection, the latency is theoretically not bound. The most reliable way to guarantee latency is to preallocate all data that will be needed by the time critical portion. If no calls to allocate memory are done, the GC will not run and so will not cause the maximum latency to be exceeded.

Smooth Operation

Related to real time programming is the need for a program to operate smoothly, without arbitrary pauses while the garbage collector stops everything to run a collection. An example of such a program would be an interactive shooter type game. Having the game play pause erratically, while not fatal to the program, can be annoying to the user.

There are several techniques to eliminate or mitigate the effect:

  • Preallocate all data needed before the part of the code that needs to be smooth is run.
  • Manually run a GC collection cycle at points in program execution where it is already paused. An example of such a place would be where the program has just displayed a prompt for user input and the user has not responded yet. This reduces the odds that a collection cycle will be needed during the smooth code.
  • Call std.gc.disable() before the smooth code is run, and std.gc.enable() afterwards. This will cause the GC to favor allocating more memory instead of running a collection pass.

Free Lists

Free lists are a great way to accelerate access to a frequently allocated and discarded type. The idea is simple - instead of deallocating an object when done with it, put it on a free list. When allocating, pull one off the free list first.

class Foo
{
    static Foo freelist;		// start of free list

    static Foo allocate()
    {   Foo f;

    if (freelist)
    {   f = freelist;
        freelist = f.next;
    }
    else
        f = new Foo();
    return f;
    }

    static void deallocate(Foo f)
    {
    f.next = freelist;
    freelist = f;
    }

    Foo next;		// for use by FooFreeList
    ...
}

void test()
{
    Foo f = Foo.allocate();
    ...
    Foo.deallocate(f);
}
Such free list approaches can be very high performance.
  • If used by multiple threads, the allocate() and deallocate() functions need to be synchronized.
  • The Foo constructor is not re-run by allocate() when allocating from the free list, so the allocator may need to reinitialize some of the members.
  • It is not necessary to practice RAII with this, since if any objects are not passed to deallocate() when done, because of a thrown exception, they'll eventually get picked up by the GC anyway.

Reference Counting

The idea behind reference counting is to include a count field in the object. Increment it for each additional reference to it, and decrement it whenever a reference to it ceases. When the count hits 0, the object can be deleted.

D doesn't provide any automated support for reference counting, it will have to be done explicitly.

Win32 COM programming uses the members AddRef() and Release() to maintain the reference counts.

Explicit Class Instance Allocation

D provides a means of creating custom allocators and deallocators for class instances. Normally, these would be allocated on the garbage collected heap, and deallocated when the collector decides to run. For specialized purposes, this can be handled by creating NewDeclarations and DeleteDeclarations. For example, to allocate using the C runtime library's malloc and free:

import std.c.stdlib;
import core.exception;
import core.memory : GC;

class Foo
{
    new(size_t sz)
    {
        void* p;

        p = std.c.stdlib.malloc(sz);

        if (!p)
            throw new OutOfMemoryError();

        GC.addRange(p, sz);
        return p;
    }

    delete(void* p)
    {
        if (p)
        {
            GC.removeRange(p);
            std.c.stdlib.free(p);
        }
    }
}

The critical features of new() are:

  • new() does not have a return type specified, but it is defined to be void*. new() must return a void*.
  • If new() cannot allocate memory, it must not return null, but must throw an exception.
  • The pointer returned from new() must be to memory aligned to the default alignment. This is 8 on win32 systems.
  • The size parameter is needed in case the allocator is called from a class derived from Foo and is a larger size than Foo.
  • A null is not returned if storage cannot be allocated. Instead, an exception is thrown. Which exception gets thrown is up to the programmer, in this case, OutOfMemory() is.
  • When scanning memory for root pointers into the garbage collected heap, the static data segment and the stack are scanned automatically. The C heap is not. Therefore, if Foo or any class derived from Foo using the allocator contains any references to data allocated by the garbage collector, the GC needs to be notified. This is done with the std.gc.addRange() method.
  • No initialization of the memory is necessary, as code is automatically inserted after the call to new() to set the class instance members to their defaults and then the constructor (if any) is run.
The critical features of delete() are:
  • The destructor (if any) has already been called on the argument p, so the data it points to should be assumed to be garbage.
  • The pointer p may be null.
  • If the GC was notified with std.gc.addRange(), a corresponding call to std.gc.removeRange() must happen in the deallocator.
  • If there is a delete(), there should be a corresponding new().

If memory is allocated using class specific allocators and deallocators, careful coding practices must be followed to avoid memory leaks and dangling references. In the presence of exceptions, it is particularly important to practice RAII to prevent memory leaks.

Custom allocators and deallocators can be done for structs and unions, too.

Mark/Release

Mark/Release is equivalent to a stack method of allocating and freeing memory. A ‘stack’ is created in memory. Objects are allocated by simply moving a pointer down the stack. Various points are ‘marked’, and then whole sections of memory are released simply by resetting the stack pointer back to a marked point.

import std.c.stdlib;
import core.exception;
import core.memory : GC;

class Foo
{
    static void[] buffer;
    static int bufindex;
    static const int bufsize = 100;

    static this()
    {
        void* p;
        p = malloc(bufsize);

        if (p is null)
            throw new OutOfMemoryError;

        GC.addRange(p, bufsize);
        buffer = p[0 .. bufsize];
    }

    static ~this()
    {
        if (buffer.length)
        {
            GC.removeRange(buffer.ptr);
            free(buffer.ptr);
            buffer = null;
        }
    }

    new(size_t sz)
    {
        void* p;

        p = &buffer[bufindex];
        bufindex += sz;

        if (bufindex > buffer.length)
            throw new OutOfMemoryError;

        return p;
    }

    delete(void* p)
    {
        assert(0);
    }

    static int mark()
    {
        return bufindex;
    }

    static void release(int i)
    {
        bufindex = i;
    }
}

void main()
{
    int m  = Foo.mark();
    Foo f1 = new Foo;           // allocate
    Foo f2 = new Foo;           // allocate

    Foo.release(m);             // deallocate f1 and f2
}

The allocation of buffer[] itself is added as a region to the GC, so there is no need for a separate call inside Foo.new() to do it.

RAII (Resource Acquisition Is Initialization)

RAII techniques can be useful in avoiding memory leaks when using explicit allocators and deallocators. Adding the scope attribute to such classes can help.

Allocating Class Instances On The Stack

Class instances are normally allocated on the garbage collected heap. However, if they:

  • are allocated as local symbols in a function and
  • are allocated using new and
  • use new with no arguments (constructor arguments are allowed) and
  • have the scope storage class

then they are allocated on the stack. This is more efficient than doing an allocate/free cycle on the instance. But be careful that any reference to the object does not survive the return of the function.

class C { ... }

scope c = new C();	// c is allocated on the stack
scope c2 = new C(5);    // allocated on stack
scope c3 = new(5) C();  // allocated by a custom allocator

If the class has a destructor, then that destructor is guaranteed to be run when the class object goes out of scope, even if the scope is exited via an exception.

Allocating Uninitialized Arrays On The Stack

Arrays are always initialized in D. So, the following declaration:

void foo()
{   byte[1024] buffer;

    fillBuffer(buffer);
    ...
}

will not be as fast as it might be since the buffer[] contents are always initialized. If careful profiling of the program shows that this initialization is a speed problem, it can be eliminated using a VoidInitializer:

void foo()
{   byte[1024] buffer = void;

    fillBuffer(buffer);
    ...
}

Uninitialized data on the stack comes with some caveats that need to be carefully evaluated before using:

  • The uninitialized data that is on the stack will get scanned by the garbage collector looking for any references to allocated memory. Since the uninitialized data consists of old D stack frames, it is highly likely that some of that garbage will look like references into the GC heap, and the GC memory will not get freed. This problem really does happen, and can be pretty frustrating to track down.
  • It's possible for a function to pass out of it a reference to data on that function's stack frame. By then allocating a new stack frame over the old data, and not initializing, the reference to the old data may still appear to be valid. The program will then behave erratically. Initializing all data on the stack frame will greatly increase the probability of forcing that bug into the open in a repeatable manner.
  • Uninitialized data can be a source of bugs and trouble, even when used correctly. One design goal of D is to improve reliability and portability by eliminating sources of undefined behavior, and uninitialized data is one huge source of undefined, unportable, erratic and unpredictable behavior. Hence this idiom should only be used after other opportunities for speed optimization are exhausted and if benchmarking shows that it really does speed up the overall execution.

Interrupt Service Routines

When the garbage collector does a collection pass, it must pause all running threads in order to scan their stacks and register contents for references to GC allocated objects. If an ISR (Interrupt Service Routine) thread is paused, this can break the program.

Therefore, the ISR thread should not be paused. Threads created with the core.thread functions will be paused. But threads created with C's _beginthread() or equivalent won't be, the GC won't know they exist.

For this to work successfully:

  • The ISR thread cannot allocate any memory using the GC. This means that the global new cannot be used. Nor can dynamic arrays be resized, nor can any elements be added to associative arrays. Any use of the D runtime library should be examined for any possibility of allocating GC memory - or better yet, the ISR should not call any D runtime library functions at all.
  • The ISR cannot hold the sole reference to any GC allocated memory, otherwise the GC may free the memory while the ISR is still using it. The solution is to have one of the paused threads hold a reference to it too, or store a reference to it in global data.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Migrating to Shared - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Migrating to Shared

Starting with dmd version 2.030, the default storage class for statics and globals will be thread local storage (TLS), rather than the classic global data segment. While most D code should just compile and run successfully without change, there can be some issues.

  1. Performance of TLS variables.
  2. Identifying TLS variables.
  3. Switch to Immutable.
  4. Marking as shared.
  5. Cowboying with __gshared.
  6. Compile errors.
  7. Link errors.

Performance of TLS variables

Yes, reading or writing TLS variables will be slower than for classic global variables. It'll be about 3 instructions rather than one. But on Linux, at least, TLS will be slightly faster than accessing classic globals using PIC (position independent code) compiler code generation settings. So it's hard to see that this would be an unacceptable problem. But let's presume it is. What can we do about it?

  1. Minimize use of global variables. Reducing the use of globals can improve the modularization and maintainability of the code anyway, so this is a worthy goal.
  2. Make them immutable. Immutable data doesn't have synchronization problems, so the compiler doesn't place it in TLS.
  3. Cache a reference to the global. Making a local cache of it, and then accessing the cached value rather than the original, can speed things up especially if the cached value gets enregistered by the compiler.
  4. Cowboy it with __gshared.

Identifying TLS variables

The first step is to find all the global variables, so they can be reviewed for disposition.

Given the complexity of source code, it isn't always easy to identify the global variables. Since it (used to be) implicit, there's no way to grep for them. It's hard to be sure you've found them all.

A new dmd compiler switch was added, -vtls. Compiling with it on will print a list of all the global variables that are now defaulting to thread local storage.

int x;

void main()
{
    static int y;
}

dmd test -vtls
test.d(2): x is thread local
test.d(6): y is thread local

Switch to Immutable

Immutable data, once initialized, never changes. This means that there are no synchronization issues with multithreading, and so no need to put immutable data into TLS. The compiler will put immutable data into classic global storage, not TLS.

A good chunk of global data falls into this category. Just mark it as immutable and it's done.

int[3] table = [6, 123, 0x87];

becomes:

immutable int[3] table = [6, 123, 0x87];

Immutability is also nice because it opens the door for further compiler optimizations.

Marking As Shared

Global data that is meant to be shared among multiple threads should be marked with the shared keyword:

shared int flag;

Not only does this cause flag to be put into classic global storage, it is also typed as being shared:

int* p = &flags;           // error, flags is shared
shared(int)* q = &flags;   // ok

The shared type attribute is transitive (like const and immutable) are. This enables static checking and sharing correctness.

Cowboying With __gshared

Sometimes, none of the above solutions will be acceptable:

  1. interfacing with C code that uses classic globals
  2. just get it working, and go back and fix it later
  3. the app is single threaded only, so no sharing issues
  4. you need every erg of performance
  5. you want to handle all the synchronization issues yourself

As D is a systems language, of course there's a way to do this. Use the storage class __gshared:

__gshared int x;

void main()
{
    __gshared int y;
}

__gshared stores the variable in the classic global data segment.

Naturally, __gshared is not allowed in safe mode.

Using __gshared makes such code easily searchable when doing QA code reviews or when going back later to fix any workarounds.

Compile Errors

The most common compiler error related to TLS will be:

int x;
int* p = &x;

test.d(2): Error: non-constant expression & x

While this works with classic global variables, it won't work with TLS variables. The reason is because TLS variables don't have a location in memory known to either the linker or the loader. It's a runtime computed value.

The solution is to initialize such things in a static constructor.

Link Errors

Sometimes you may encounter strange error messages from the linker about the global variables. These are nearly always caused by one module putting the variable in TLS, and another putting that same variable in classic global storage. This can happen when linking code with libraries that were built with earlier versions of dmd. Check that libphobos2.a was properly replaced with the latest. It can also happen when interfacing with C. C globals default to being classic global, although C does support TLS declarations. Make sure the corresponding D declarations match the C ones in terms of TLS or classic global.

int x;
extern int y;
__thread int z;

extern (C)
{
    extern shared int x;
    shared int y;
    extern int z;
}
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Mixins - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Mixins

Mixins (not to be confused with template mixins) enable string constants to be compiled as regular D code and inserted into the program. Combining this with compile time manipulation of strings enables the creation of domain-specific languages.

For example, here we can create a template that generates a struct with the named members:

template GenStruct(string Name, string M1)
{
    const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}

mixin(GenStruct!("Foo", "bar"));

which generates:

struct Foo { int bar; }

Superficially, since D mixins can manipulate text and compile the result, it has some similar properties to the C preprocessor. But there are major, fundamental differences:

  • The C preprocessing step occurs before lexical analysis. This makes it impossible to lex or parse C without access to all of the context, including all #include'd files, paths and all relevant compiler switches. Mixins occur during semantic analysis, and do not affect the lexing or parsing process. Lexing and parsing can still occur without semantic analysis.
  • The C preprocessor can be used to create what appears to be different syntax:
    #define BEGIN {
#define END   }

BEGIN
  int x = 3;
  foo(x);
END
    This monkey business is impossible with mixins. Mixed in text must form complete declarations, statements, or expressions.
  • C macros will affect everything following that has the same name, even if they are in nested scopes. C macros cut across all scopes. This problem is called being not "coding hygenic". Mixins follow the usual scoping rules, and is hygenic.
  • C preprocessing expressions follow a different syntax and have different semantic rules than the C language. The C preprocessor is technically a different language. Mixins are in the same language.
  • C const declarations and C++ templates are invisible to C preprocessing. Mixins can be manipulated using templates and const declarations.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Regular expressions - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Regular expressions

by Dmitry Olshansky, the author of std.regex

Introduction

String processing is a kind of daily routine that most applications do in a one way or another. It should come as no wonder that many programming languages have standard libraries equipped with a variety of specialized functions for common string manipulation needs. The D programming language standard library among others offers a nice assortment in std.string, as well as generic functions from std.algorithm that work with strings. Still no amount of fixed functionality could cover all needs, as naturally flexible text data needs flexible solutions.

Here is where regular expressions come in handy, often succinctly called as regexes. Regexes are simple yet powerful language for defining patterns of strings, put together with a substitution mechanism, they form a Swiss Army knife of text processing. They are considered so useful that a number of languages provides built-in support for regular expressions. This does not nessary mean that built-in implies faster processing or more features. It's more a matter of providing convenient and friendly syntax for typical operations and usage patterns.

The D programming language provides a standard library module std.regex. Being a highly expressive systems language, D allows regexes to be efficiently implemented within the language itself, yet have the same level of readability and usability as built-in version would provide. We'll see below how close to built-in regexes look and feel we can achieve.

By the end of article you'll have a good understanding of regular expression capabilities in this library, and how to utilize its API in a most straightforward way. Examples in this article assume that the reader has fairly good understanding of regex elements, yet it's not required to understand the API.

A warm up

How do you check if something is a phone number by looking at it?

Yes, it's something with numbers, and there may be a country code in front of that... Ok, going for an international format should make it more strict. As this is the first time, let's put together a full program:

import std.stdio, std.regex;
void main(string argv[]){
    string phone = argv[1]; //assuming phone is passed as first argument on the command line
    if(match(phone, r"^\+[1-9][0-9]* [0-9 ]*$"))
        writeln("It looks like a phone number.");
    else
        writeln("Nope, it's not a phone number.");
}
And that's it! Just keep in mind the boundaries of regular expressions power - to truly establish a validness of a phone number, one has to try dialing it or contact the authority.

Now, come to think of it, this tiny sample showed a lot of useful things already:

  • a raw string literal of form r"...", that allows writing a regex pattern in its natural notation
  • match function, is an universal tool that we'll see in other work scenarios as well. To check if there was a match on a string, just test the return value explicitly as boolean.
  • when trying to match special regex characters like +, *, (, ), [, ] and $ don't forget to use escaping with \
  • Unless there is a lot of text processing going on, it's OK to pass a plain string as a pattern. The internal representation used to do the actual work is cached, to speed up subsequent calls.

Continuing with the phone number example, it could be useful to get the exact value of country code, as well as the whole number. For the sake of experiment let's also explicitly store compiled regex pattern via regex to see how it works.

string phone = "+31 650 903 7158"; //fictional, any coincidence is just that
auto phoneReg = regex(r"^\+([1-9][0-9]*) [0-9 ]*$");
auto m = match(phone, phoneReg);
assert(m);
assert(m.captures[0] == "+31 650 903 7158");
assert(m.captures[1] == "31");
//you shouldn't really care about the type of regex object,
//but here it is
static assert(is(typeof(phoneReg) : Regex!char));

To search and replace

There is a frequent need to find all matches in piece of text. Picking an easy task, let's see how to filter out all white space-only lines. There is no special routine for looping over input like search() or similar as found in some libraries. Instead std.regex provides a natural syntax for looping over all matches via plain foreach.

auto buffer = std.file.readText("regex.d");
foreach(m; match(buffer, regex(r"^.*[^\p{WhiteSpace}]+.*$","gm"))){
    writeln(m.hit); //hit is a shorthand for m.captures[0]
}

It just works as the result of match is an input range. An element type is Captures for the string type being used, it is a random access range of submatches. I won't go into full detail of the range concept, suffice to say, that it's a primary way of representing sequences of data in D. Random access here implies one can peek at any element with direct indexing. To have a feeling of how this affects the API:

auto m = match("Ranges are hot!", r"(\w)\w*(\w)"); //at least 3 "word" symbols
assert(m.front[0] == "Ranges");
//m.captures is a historical alias for the first element of match range (.front).
assert(m.captures[1] == m.front[1]);
auto captures = m.front;
assert(captures[2] == "s");
foreach(c; captures)
    writeln(c); //will show lines: Ranges, R, s

By playing by the rules std.regex gets some nice benefits in interaction with other modules e.g. this is how one could count non-empty lines in text buffer (just don't forget to import std.algorithm when trying that at home):

auto buffer = std.file.readText("regex.d");
int count = count(match(text, regex(r"^.*\P{WhiteSpace}+.*$","gm")));

This by the way tells me that std.regex has 7128 non-blank lines as of this writing. But let's get back to the regular expression itself. A seasoned regex user catches instantly that Unicode properties are supported with perl-style \p{xxx}, to spice that all of Scripts and Blocks are supported. Let us dully note that \P{xxx} means not having an xxx property, i.e here not a white space character. Refer to the Unicode standard UTS 18 for full list and specific details.

Another thing of importance is the option string - "gm", where g stands for global and m for multi-line mode. While global is obvious in this context, what multi-line mode does deserves some explanation.

Historically utilities that supported regex patterns (unix grep, sed, etc.) processed text line by line. At that time anchors like ^, $ meant the start of the whole input buffer that has been same as that of line. As regular expressions became more ubiquitous the need to recognize multiple lines in a chunk of text, with anchors ^ & $ matching before and after line break literally. For the curious, line break is defined as (\n | \v | \r | \f | \u0085 | \u2028 | \u2029 | \r\n). Needless to say, one need not to turn on multi-line mode if not using any of ^, $.

Now that search was covered, the topic suggest that it's about time to do some replacements. For instance to replace all dates in a text from "MM/dd/YYYY" format to a sortable version of "YYYY-MM-dd":

auto text = readText(...);
auto replaced = replace(text,
    regex(r"([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})","g"), "$3-$1-$2");

The "all dates" part comes from the fact that regex has global option set, omit it to replace only the first occurrence. As seen the replacement is controlled by format string not unlike one in C's famous printf. The $1, $2, $3 substituted with content of sub-expresions. Aside from referencing sub-matches, one can include the whole part of input preceding the match via $` and $' for the content following right after the match.

Ok, now let's aim for something bigger, this time to show that std.regex can do things that are unattainable by classic textual substitution alone. Imagine you want to translate a web shop catalog so that it display prices in your currency. Yes, one can use calculator or estimate it, once having current ratio. Being programmers we can do better, so let's wrap up a simple program that converts text to use correct prices everywhere. For the sake of example let it be UK pounds and US dollars.

import std.conv, std.regex, std.range, std.file, std.stdio;
import std.string : format;

void main(string[] argv){
    immutable ratio = 1.5824; //UK pounds to US dollar as of this writing
    auto to_dollars(Captures!string price){
        real value = to!real(price["integer"]);
        if(!price["fraction"].empty)
            value += 0.01*to!real(price["fraction"]);
        return format("$%.2f",value * ratio);
    }
    string text = std.file.readText(argv[1]);
    auto converted = replace!to_dollars(text,
            regex(r"£\s*(?P<integer>[0-9]+)(\.(?P<fraction>[0-9]{2}))?","g"));
    write(converted);
}

Getting current conversion rates and supporting more currencies is left as an exercise for the reader. What at work here is so-called replace with delegate, analogous to a callout ability found in other languages and regex libraries. The magic is simple: whenever replace finds a match it calls a user supplied callback on the captured piece, then it uses the return value as replacement. And so on for other matches, given the "g" flag of regex.

I couldn't resist to spice this example up with yet another feature - named groups. Names work just like opaque aliases for numbers of captured subexpressions. Meaning that with the same exact regular expression one could as well change these lines to:

real value = to!real(price[1]);
if(!price[3].empty)
            value += 0.01*to!real(price[3]);
Though that lacks readability and is not future proof. Also note that optional captures are still represented, it's just they can be an empty string if not matched.

More features, more options

As core functionallity was already presented, let's move on to extras. Sometimes it's useful to do almost the opposite of searching - split up input using regex as separator. Like the following sample, that outputs text by sentences:

foreach(sentence; splitter(argv[1], regex(r"(?<=[.?!]+(?![?!]))\s*")))
    writeln(sentence);

Again the type of splitter is range, thus allowing foreach iteration. Notice the usage of lookaround in regex, it's a neat trick here as stripping off final punctuation is not our intention. Breaking down this example, (?<=[.?!]) part looks behind for first ., ? or !. This get us half way to our goal because \s* also matches between elements of punctuation like "?!", so a negative lookahead is introduced inside lookbehind to make sure we are past all of the punctuation marks. Admittedly, barrage of ? and ! makes this regex rather obscure, more then it's actually is. Observe that there are no restrictions on contents of lookaround expressions, one can go for lookahead inside lookbehind and so on. However in general it's recommended to use them sparingly, keeping them as weapon of last resort.

Now for something completely different yet exactly the same. For one, there is an ability to precompile constant regex at compile-time:

static r = regex("Boo-hoo");
assert(match("What was that? Boo-hoo?", r));

Importantly it's the exact same Regex object that works through all of the API we've seen so far. It's just takes less then 1 μs of run-time to initialize. Run-time version took around 10-20 μs on my machine, keep in mind that it was a trivial pattern.

Now stepping futher in this direction there is an ability to construct specialized native machine code that matches a given regex to speed up matching. All of this at compile time, and again the module usage stays consistent!

Recalling the phone number example:

//It's only a 5 characters difference!
string phone = "+31 650 903 7158";
auto phoneReg = ctRegex!r"^\+([1-9][0-9]*) [0-9 ]*$";
auto m = match(phone, phoneReg);
assert(m);
assert(m.captures[0] == "+31 650 903 7158");
assert(m.captures[1] == "31");

In this particular case it matched roughly 50% faster for me though I haven't done comprehensive analysis of this case. Not to spoil the excitement, but as of this writing the feature is experimental and temporarily lacks some extensions. Continuing the gloomy trend, be warned that compiler might choke on it, and it's also less tested. That being said, there is no doubt ctRegex facility will only improve over time. So start with run-time version, then go compile-time if willing to experiment or when need to squeeze out some more performance.

Conclusion

The article represents a walkthrough of std.regex focused on showcasing the API. By following a series of easy yet meaningful tasks, its features are exposed in combinations, that underline the elegance and flexibility of this library solution. The good thing that not only the API is natural, but it also follows established standards and integrates well with the rest of Phobos. Putting together its major features for a short-list, std.regex is:

  • Fully Unicode-aware, qualifies to standard full level 1 Unicode support
  • Lots of modern extensions, including unlimited generalized lookaround. It makes porting regexes from other libraries a breeze
  • Lean API that consists of a few flexible tools: match, replace, splitter
  • Uniform and powerful, with unique abilities like precompiling regex or using ctRegex specially tailored engine at compile-time. All of this fits within the common interface without a notch.

The format of this article is intentionally more of an overview, as such it doesn't stop to talk in-depth about certain capabilities like case-insensitive matching (via simple casefolding rules of Unicode), backreferences, lazy quantifiers. And even more features are coming, as there are interesting opportunities not exploited.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


SafeD - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

SafeD

by Bartosz Milewski, a member of the D design team

I've seen some very good programmers move away from C++ in favor of languages like Java or C#. Being a hard-core C++ programmer myself, I wondered why anyone would want to switch to a less powerful and less efficient language. Mind you, I could understand why a newcomer would opt for a simpler, flatter-learning-curve language but, once somebody invested the time and effort to become proficient in C++, why in the world would they want to abandon it?

The universal reason I've heard from the turncoats was “productivity.” The consensus seems to be that programmers are more productive using Java, C#, Ruby, or Python then they are using C++.

What are the major impediments to productive programming in C++?

Horrible syntax is one. This is actually more serious than it sounds. A good programmer can probably master some pretty horrible syntaxes given enough time. The problem is that C++ syntax and grammar is not only human-unfriendly but also parser-hostile. The fact that the Java market is saturated with productivity boosting tools is the reflection of the language's parseability. I have to yet see a C++ programming environment that would offer such powerful refactoring tools as are commonplace in Java.

Language safety is the other major factor. C++ is notorious for presenting a never ending gallery of opportunities to shoot yourself in the foot. In fact C++ not only provides the opportunity to write dangerous code, it encourages it. At some point a major C++ compiler vendor marked a portion of STL algorithms as "deprecated" because of safety concerns. In particular the C++ Standard Library, in accordance with the spirit of C++, extends the number of ways a buffer overflow bug might sneak into your program.

One notorious example is the std::swap_ranges algorithm, which takes three iterators. The first two iterators are supposed to delimit one range, the third one marks the beginning of the second range. No testing is done whether the second range doesn't extend past the end of the container. When it does, virus writers rejoice!

The pipe dream of programming language designers is to be able to guarantee that if a program compiles successfully, it will work. Of course you have to be reasonable about your definition of a "working" program. For instance, you might require that the program will never get "stuck"—a term which has a precise meaning in computer science, but loosely means that the program will not GP-fault on you (it is stuck in the sense that there is no well-defined system-independent next step). Languages that have such a property are called "sound".

Guess what, there is a well-defined (and meaningful) subset of Java that is sound. Real-life Java programs, for practical reasons, stray outside of this sound subset; but at least the use of unsafe features is less prevalent and easier to spot in a Java program than it is in a C++ program. In practice, a Java compiler will detect more bugs in your program than a C++ compiler, and that translates directly into less time spent debugging—ergo, higher productivity.

So what are the good features of C++?

Performance is one. It's really hard to beat C++ performance. If your program has to be fast and responsive you have little choice but to write it in C++ (or, in rare cases, in C or assembly).

Then there are the low-level features of C++ that let you write programs interacting directly with hardware. For instance, C and C++ are still kings of embedded programming.

C++ offers powerful abstractions, in particular the ability to write generic code. Java and C# have their own generics but they are feeble compared to what C++ has to offer.

All these features make C++ an ideal language for writing operating systems. Operating systems are huge programs that have to be fast and interact directly with hardware. But even outside operating systems there are a lot of applications that have to be large and fast.

So it looks like the programming world could be nicely partitioned between C++, Java, C# and the likes. And it all makes sense as long as you believe in the unavoidability of tradeoffs. But there is no law of nature that says, You have to trade productivity for power.

What about a language that is built like an onion. It has a reasonably simple and safe core, which is not unlike Java or C#. A programmer can quickly master a safe subset of it and be as productive as a Java programmer (if not more). And what if the safe subset offered performance that was comparable to C++?

And then, the same language has outer layers that can be mastered gradually, as the need arises. It offers low-level features to grind the hardware, and high-level features to generate code on demand. It offers modularity and implementation hiding. It has unrivaled compile time features that enable lightning fast runtime performance.

I'll let you in on a secret, this language is D.

Programming Pitfalls

Did you know that the famous "Hello World!" program, which is usually the first program people write in C, exposes some of the most dangerous features of the language? It contains this statement:

printf ("Hello World!\n");
Consider the signature of printf:
int printf (const char * restrict format, ...);

(restrict is a new C keyword.) First of all, it's a function that takes a variable number of arguments. The number and the types of arguments are encoded in the format string.

When is the match between the format and the argument list checked? Not at compile time—the compiler has no understanding of the format string (although some compilers may issue warnings if the string is statically known). At runtime then? Well, guess again. Consider this: If the programmer makes a mistake of calling printf with too few arguments, he or she will not get a nice error code or exception. Here's what the C Standard says about this situation:

If there are insufficient arguments for the format, the behavior is undefined.

Undefined behavior is the worst thing that may happen to a program. If you're lucky, the program will fault and terminate without prejudice. If you're not so lucky, the program will continue in a compromised state and, in the worst case, it will execute malicious code that will take over your computer.

The second dangerous feature of printf is its use of a pointer. It is up to the diligence of the programmer to ensure that a pointer points to a valid piece of data. In the "Hello World!" example, the pointer points to a null-terminated static string, so we're fine. But the following program will compile too:

char * format = 0;
printf (format);

Guess what happens. Inside printf the pointer is dereferenced and then all bets are off. Again, citing the C Standard,

If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

Let's talk about pointers some more. Every memory allocation returns a valid pointer (unless the program runs out of memory). You might think that dereferencing such a pointer would be safe. That is correct as long as your program doesn't free the allocated memory thus ending the lifetime of the object. After that, you are dealing with a dangling pointer and all bets are off. Again, C Standard is pretty upfront about it.

Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.

As you can see, C was not designed for the faint of heart. It's a low-level language and the programmer better know what he or she is doing or suffer the consequences.

C++ is different though, right?

Throughout its history, C++ has been struggling with C legacy. A lot of constructs have been provided to patch the unsafe features of C. For instance, the "Hello World!" program in C++ might be transformed to a safer version.

std:cout << "Hello World!" << std::endl;

There is no variable argument count, and the std::cout object is smart enough to understand the types of arguments passed to it (still, many programmers continue using printf in C++, if only for its syntactic simplicity).

Unlike in C, memory allocation in C++ is typed and combined with object construction (as long as you stay away from malloc and free). That's the good part. However, objects still have to be explicitly recycled (deleted). And after recycling, the program is still left with dangling pointers, whose dereferencing—you guessed it—leads to undefined behavior.

Whereas pointers were important in C, C++ embraced them as the main vehicle for the Standard Library. STL algorithms use iterators, objects that are either pointers themselves or imitate the behavior (and the pitfalls) of pointers. Just like with pointers, a programmer's error in using iterators leads to undefined behavior (see the swap_range example).

In response to C/C++'s inherent lack of safety, languages like Java and C# took a different path. They either ban pointers altogether or relegate them to special "unsafe" blocks. Memory management, with its risk of accessing recycled data, is taken away from the programmer and dealt with by automatic garbage collection. There are many other simplifications and safety improvements over C++. Unfortunately they all come at the expense of expressive power and performance.

The SafeD Subset

In D, we expect the vast majority of programmers to operate within the safe subset of D, which we call SafeD. The safety and the ease of use of SafeD is comparable to Java—in fact Java programs can be machine-translated into this safe subset of D. SafeD is easy to learn and it keeps the programmers away from undefined behaviors. It is also very efficient.

When you enter SafeD, you leave your pointers, unchecked casts and unions at the door. Memory management is provided to you courtesy of Garbage Collection. Class objects are passed around using opaque handles. Arrays and strings are bound-checked (it's possible to turn the checks off with a compiler switch, but then you're no longer in SafeD). You may still write code that will throw a runtime exception (e.g., array out-of-bounds error, or uninitialized-class-object error), but you won't be able to overwrite memory that hasn't been allocated to you or that has already been recycled.

Let's look at the "Hello World!" program in D. On the face of it, it's not much different than its C counterpart:

writeln ("Hello Safe World!");

The function writeln is the equivalent of the C printf (more precisely, it's the representative of a family of output functions including write and its formatting versions, writef and writefln). Just like printf, writeln accepts a variable number of arguments of arbitrary types. But here the similarity ends. As long as you pass SafeD-arguments to writeln, you are guaranteed not to encounter any undefined behavior. Here, writeln is called with a single argument of the type string. In contrast to C, D string is not a pointer. It is an array of immutable char, and arrays are a built into the safe subset of D.

You might be interested to know how the safety of writeln is accomplished in D. One possible approach would have been to make writeln a compiler intrinsic, so that correct code would be generated on a case-by-case basis. The beauty of D is that it gives a sophisticated programmer tools that allow such case-by-case code generation of code. The advanced features used in the implementation of writeln are:

  • Compile-time code generation using templates, and
  • A safe mechanism for dealing with variable number of arguments using tuples.

SafeD Libraries

One of the major differences between Java and D is that D has enough power to let an advanced programmer implement libraries that can be used within SafeD.

A lot of advanced features of D are compatible with SafeD, as long as they don't force the user to use unsafe types. For instance, a library may provide the implementation of a generic list. The list can be instantiated with any type, in particular with a pointer type. A list of pointers, by definition, cannot be safe, because pointer arithmetic is unsound. However, a list of ints or class objects can and should be safe. That's why such ageneric lists can be used in SafeD, even though their usage outside of SafeD may be unsafe.

Moreover, it might be more efficient to base the internal implementation of a list on pointers. As long as these pointers are not exposed to the client, such an implementation might be certified to be SafeD compatible1 . You can have a cake (advanced features of D) and eat it too (take advantage of them in SafeD).

One User's Experience

Even before I came up with the idea of SafeD2, I tried to restrict myself to the safe subset of D for most of my projects. I was surprised how much could be accomplished and how my productivity soared. I also showed SafeD to my co-worker, a C++ programmer, and he was able to learn it in a very short time.

So far my experience has been that if a SafeD program compiles without errors then, in a vast majority of cases, it runs without errors, and does what I want it to do. That definitely hasn't been my experience with C++.

What is even more surprising to me is that I was able to accomplish all that with almost non-existing support from tools and with a compiler that excels in cryptic error messages. D is still lacking a lot of infrastructure, but I can imagine how easy programming will be when a critical mass of productivity tools sprouts around it. And unlike C++, D is easy to parse and its front end is open source. So there are no barriers to entry for tool writers.

Footnotes

  1. There is no central authority to issue such certifications, each library provider has to establish a level of trust with its clients. In particular, you should expect the D standard library to be SafeD certified by the compiler provider.
  2. The name, SafeD, was proposed by David B. Held.

Acknowledgments

Many thanks go to the rest of the D design team for valuable feedback and corrections to this article

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Templates Revisited - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Templates Revisited

by Walter Bright, http://www.digitalmars.com/d

What I am going to tell you about is what we teach our programming students in the third or fourth year of graduate school... It is my task to convince you not to turn away because you don't understand it. You see my programming students don't understand it... That is because I don't understand it. Nobody does.

Richard Deeman

Abstract

Templates in C++ have evolved from little more than token substitution into a programming language in itself. Many useful aspects of C++ templates have been discovered rather than designed. A side effect of this is that C++ templates are often criticized for having an awkward syntax, many arcane rules, and being very difficult to implement properly. What might templates look like if one takes a step back, looks at what templates can do and what uses they are put to, and redesign them? Can templates be powerful, aesthetically pleasing, easy to explain and straightforward to implement? This article takes a look at an alternative design of templates in the D Programming Language [1].

Similarities

  • compile time semantics
  • function templates
  • class templates
  • type parameters
  • value parameters
  • template parameters
  • partial and explicit specialization
  • type deduction
  • implicit function template instantiation
  • SFINAE (Substitution Failure Is Not An Error)

Argument Syntax

The first thing that comes to mind is the use of < > to enclose parameter lists and argument lists. < > has a couple serious problem, however. They are ambiguous with operators <, >, and >>. This means that expressions like:

a<b,c>d;
and:
a<b<c>>d;

are syntactically ambiguous, both to the compiler and the programmer. If you run across a<b,c>d; in unfamiliar code, you've got to slog through an arbitrarily large amount of declarations and .h files to figure out if it is a template or not. How much effort has been expended by programmers, compiler writers, and language standard writers to deal with this?

There's got to be a better way. D solves it by noticing that ! is not used as a binary operator, so replacing:

a<b,c>

with:

a!(b,c)

is syntactically unambiguous. This makes it easy to parse, easy to generate reasonable error messages for, and makes it easy for someone inspecting the code to determine that yes, a must be a template.

Template Definition Syntax

C++ can define two broad types of templates: class templates, and function templates. Each template is written independently, even if they are closely related:

template<class T, class U> class Bar { ... };

template<class T, class U> T foo(T t, U u) { ... }

template<class T, class U> static T abc;

POD (Plain Old Data, as in C style) structs bring together related data declarations, classes bring together related data and function declarations, but there's nothing to logically group together templates that are to be instantiated together. In D, we can write:

template Foo(T, U)
{
  class Bar { ... }

  T foo(T t, U u) { ... }

  T abc;

  typedef T* Footype;	// any declarations can be templated
}

The Foo forms a name space for the templates, which are accessed by, for example:

Foo!(int,char).Bar b;
Foo!(int,char).foo(1,2);
Foo!(int,char).abc = 3;

Of course, this can get a little tedious, so one can use an alias for a particular instantiation:

alias Foo!(int,char) f;
f.Bar b;
f.foo(1,2);
f.abc = 3;

For class templates, there's an even simpler syntax. A class is defined like:

class Abc
{
    int t;
    ...
}

This can be turned into a template by just adding a parameter list:

class Abc(T)
{
    T t;
    ...
}

Template Declaration, Definition, and Export

C++ templates can be in the form of a template declaration, a template definition, and an exported template. Because D has a true module system, rather than textual #include files, there are only template definitions in D. The need for template declarations and export is irrelevant. For example, given a template definition in module A:

module A;

template Foo(T)
{
    T bar;
}

it can be accessed from module B like:

module B;

import A;

void test()
{
    A.Foo!(int).bar = 3;
}

As usual, an alias can be used to simplify access:

module B;

import A;
alias A.Foo!(int).bar bar;

void test()
{
    bar = 3;
}

Template Parameters

C++ template parameters can be:

  • types
  • integral values
  • static/global addresses
  • template names

D template parameters can be:

  • types
  • integral values
  • floating point values
  • string literals
  • templates
  • or any symbol

Each can have default values, and type parameters can have (a limited form of) constraints:

class B { ... }
interface I { ... }

class Foo(
  R,            // R can be any type
  P:P*,         // P must be a pointer type
  T:int,        // T must be int type
  S:T*,         // S must be pointer to T
  C:B,          // C must be of class B or derived
                // from B
  U:I,          // U must be interface I, or any interface
                // or class which has interface I in its
                // inheritance tree
  string str = "hello",
                // string literal,
                // default is "hello"
  alias A = B   // A is any symbol
                // (including template symbols),
                // defaulting to B
  )
{
    ...
}

Specialization

Partial and explicit specialization work as they do in C++, except that there is no notion of a ‘primary’ template. All the templates with the same name are examined upon template instantiation, and the one with the best fit of arguments to parameters is instantiated.

template Foo(T) ...
template Foo(T:T*) ...
template Foo(T, U:T) ...
template Foo(T, U) ...
template Foo(T, U:int) ...

Foo!(long)       // picks Foo(T)
Foo!(long[])     // picks Foo(T), T is long[]
Foo!(int*)       // picks Foo(T*), T is int
Foo!(long,long)  // picks Foo(T, U:T)
Foo!(long,short) // picks Foo(T, U)
Foo!(long,int)   // picks Foo(T, U:int)
Foo!(int,int)    // ambiguous - Foo(T, U:T)
                 // or Foo(T, U:int)

Two Level Name Lookup

C++ has some unusual rules for name lookup inside templates, such as not looking inside base classes, not allowing scoped redeclaration of template parameter names, and not considering overloads that happen after the point of definition (this example is derived from one in the C++98 Standard):

int g(double d) { return 1; }

typedef double A;

template<class T> struct B
{
  typedef int A;
};

template<class T> struct X : B<T>
{
  A a;              // a has type double
  int T;            // error, T redeclared
  int foo()
  {  char T;        // error, T redeclared
     return g(1);   // always returns 1
  }
};

int g(int i) { return 2; }	// this definition not seen by X

Scoped lookup rules in D match the rules for the rest of the language:

int g(double d) { return 1; }

alias double A;

class B(T)
{
    alias int A;
}

class X(T) : B!(T)
{
  A a;             // a has type int
  int T;           // ok, T redeclared as int
  int foo()
  {   char T;      // ok, T redeclared as char
      return g(1);  // always returns 2
  }
};

int g(int i) { return 2; }	// functions can be forward referenced

Template Recursion

Template recursion combined with specialization means that C++ templates actually form a programming language, although certainly an odd one. Consider a set of templates that computes a factorial at run time. Like "hello world" programs, factorial is the canonical example of template metaprogramming:

template<int n> class factorial
{
  public:
    enum
    {
      result = n * factorial<n - 1>::result
    };
};

template<> class factorial<1>
{
  public:
    enum { result = 1 };
};

void test()
{
  // prints 24
  printf("%d\n", factorial<4>::result);
}

Recursion works as well in D, though with significantly less typing:

template factorial(int n)
{
  const factorial = n * factorial!(n-1);
}

template factorial(int n : 1)
{
  const factorial = 1;
}

void test()
{
  writefln(factorial!(4));  // prints 24
}

Through using the static if construct it can be done in just one template:

template factorial(int n)
{
  static if (n == 1)
    const factorial = 1;
  else
    const factorial = n * factorial!(n-1);
}

reducing 13 lines of code to an arguably much cleaner 7 lines. static if's are the equivalent of C++'s #if. But #if cannot access template arguments, so all template conditional compilation must be handled with partial and explicitly specialized templates. static if dramatically simplifies such constructions.

D can make this even simpler. Value generating templates such as the factorial one are possible, but it's easier to just write a function that can be computed at compile time:

int factorial(int n)
{
  if (n == 1)
    return 1;
  else
    return n * factorial(n - 1);
}

static int x = factorial(5);  // x is statically initialized to 120

SFINAE (Substitution Failure Is Not An Error)

This determines if the template's argument type is a function, from "C++ Templates: The Complete Guide", Vandevoorde & Josuttis pg. 353:

template<U> class IsFunctionT
{
  private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template static One test(...);
    template static Two test(U (*)[1]);
  public:
    enum {
      Yes = sizeof(IsFunctionT::test(0)) == 1
    };
};

void test()
{
  typedef int (fp)(int);

  assert(IsFunctionT<fp>::Yes == 1);
}

Template IsFunctionT relies on two side effects to achieve its result. First, it relies on arrays of functions being an invalid C++ type. Thus, if U is a function type, the second test will not be selected since to do so would cause an error (SFINAE (Substitution Failure Is Not An Error)). The first test will be selected. If U is not a function type, the second test is a better fit than ... . Next, it is determined which test was selected by examining the size of the return value, i.e. sizeof(One) or sizeof(Two). Unfortunately, template metaprogramming in C++ often seems to be relying on side effects rather than being able to expressly code what is desired.

In D this can be written:

template IsFunctionT(T)
{
  static if ( is(T[]) )
    const int IsFunctionT = 0;
  else
    const int IsFunctionT = 1;
}

void test()
{
  alias int fp(int);

  assert(IsFunctionT!(fp) == 1);
}

The is(T[]) is the equivalent of SFINAE (Substitution Failure Is Not An Error). It tries to build an array of T, and if T is a function type, it is an array of functions. Since this is an invalid type, the T[] fails and is(T[]) returns false.

Although SFINAE (Substitution Failure Is Not An Error) can be used, the is expressions can test a type directly, so it isn't even necessary to use a template to ask questions about a type:

void test()
{
  alias int fp(int);

  assert( is(fp == function) );
}

Template Metaprogramming With Floats

Let's move on to things that are impractical with templates in C++. For example, this template returns the square root of real number x using the Babylonian method:

import std.stdio;

template sqrt(real x, real root = x/2, int ntries = 0)
{
  static if (ntries == 5)
    // precision doubles with each iteration,
    // 5 should be enough
    const sqrt = root;
  else static if (root * root - x == 0)
    const sqrt = root;  // exact match
  else
    // iterate again
    const sqrt = sqrt!(x, (root+x/root)/2, ntries+1);
}

void main()
{
    real x = sqrt!(2);
    writefln("%.20g", x); // 1.4142135623730950487
}

Literal square roots are often needed for speed reasons in other runtime floating point computations, such as computing the gamma function. These template floating point algorithms need not be efficient as they are computed at compile time, they only need to be accurate.

Much more complex templates can be built, for example, Don Clugston has written a template to compute π at compile time. [2]

Again, we can just do this with a function that can be executed at compile time:

real sqrt(real x)
{
    real root = x / 2;
    for (int ntries = 0; ntries < 5; ntries++)
    {
    if (root * root - x == 0)
        break;
    root = (root + x / root) / 2;
    }
    return root;
}
static y = sqrt(10);   // y is statically initialized to 3.16228

Template Metaprogramming With Strings

Even more interesting things can be done with strings. This example converts an integer to a string at compile time:

template decimalDigit(int n)	// [3]
{
  const string decimalDigit = "0123456789"[n..n+1];
}

template itoa(long n)
{
  static if (n < 0)
     const string itoa = "-" ~ itoa!(-n);
  else static if (n < 10)
     const string itoa = decimalDigit!(n);
  else
     const string itoa = itoa!(n/10L) ~ decimalDigit!(n%10L);
}

string foo()
{
  return itoa!(264);   // returns "264"
}

This template will compute the hash of a string literal:

template hash(char [] s, uint sofar=0)
{
   static if (s.length == 0)
      const hash = sofar;
   else
      const hash = hash!(s[1 .. length], sofar * 11 + s[0]);
}

uint foo()
{
    return hash!("hello world");
}

Regular Expression Compiler

How do D templates fare with something much more significant, like a regular expression compiler? Eric Niebler has written one for C++ that relies on expression templates. [4] The problem with using expression templates is that one is restricted to using only C++ operator syntax and precedence. Hence, regular expressions using expression templates don't look like regular expressions, they look like C++ expressions. Eric Anderton has written one for D that relies on the ability of templates to parse strings. [5] This means that, within the strings, one can use the expected regular expression grammar and operators.

The regex compiler templates parse the regex string argument, pulling off tokens one by one from the front, and instantiating custom template functions for each token predicate, eventually combining them all into one function that directly implements the regular expression. It even gives reasonable error messages for syntax errors in the regular expression.

Calling that function with an argument of a string to match returns an array of matching strings:

import std.stdio;
import regex;

void main()
{
    auto exp = &regexMatch!(r"[a-z]*\s*\w*");
    writefln("matches: %s", exp("hello    world"));
}

What follows is a cut-down version of Eric Anderton's regex compiler. It is just enough to compile the regular expression above, serving to illustrate how it is done.

module regex;

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 n = regexCompile!(pattern).fn(str);
    if (n != testFail && n > 0)
      results ~= str[0..n];
    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)
{
  int testUnion(string str)
  {
    int n1 = testFirst(str);
    if (n1 != testFail)
    {
      int n2 = testSecond(str[n1 .. $]);
      if (n2 != testFail)
        return n1 + n2;
    }
    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)
{
  int testZeroOrMore(string str)
  {
    if (str.length == 0)
      return 0;
    int n = testPredicate(str);
    if (n != testFail)
    {
      int n2 = testZeroOrMore!(testPredicate)(str[n .. $]);
      if (n2 != testFail)
        return n + n2;
      return n;
    }
    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..1] ~ 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..1] ~ next.token;
      const uint consumed = next.consumed+1;
    }
  }
  else static if (fuzzy)
  {
    const string token = "";
    const uint consumed = 0;
  }
  else
  {
    pragma(msg,"Error: expected " ~
               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 char following '-' in char 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 .. $];
    }
    alias regexCompileCharClassRecurse!(termFn,remaining) recurse;
    alias recurse.fn fn;
    const uint consumed = recurse.consumed + thisConsumed;
  }
  else
  {
    alias testEmpty!() fn;
    const uint consumed = 0;
  }
}

/**
 * Used to recursively parse character class.
 * Params:
 *  termFn = generated function up to this point
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function including termFn and
 *       parsed character class
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompileCharClassRecurse(alias termFn,string pattern)
{
  static if (pattern.length > 0 && pattern[0] != ']')
  {
    alias regexCompileCharClass2!(pattern) next;
    alias testOr!(termFn,next.fn,pattern) fn;
    const uint consumed = next.consumed;
  }
  else
  {
    alias termFn 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
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompilePredicate(alias test, string pattern)
{
  static if (pattern.length > 0 && pattern[0] == '*')
  {
    alias testZeroOrMore!(test) fn;
    const uint consumed = 1;
  }
  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..pattern.length]) 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, next) term;
    const string remaining = next[term.consumed .. next.length];

    alias regexCompileRecurse!(term,remaining).fn fn;
  }
  else
    alias testEmpty!() fn;
}

template regexCompileRecurse(alias term,string pattern)
{
  static if (pattern.length > 0)
  {
    alias regexCompile!(pattern) next;
    alias testUnion!(term.fn, next.fn) fn;
  }
  else
    alias term.fn 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] == '^' ||
    pattern[0] == '\\'
  )
    const isSpecial = true;
  else
    const isSpecial = false;
}

More Template Metaprogramming

  1. Tomasz Stachowiak's compile time raytracer.
  2. Don Clugston's compile time 99 Bottles of Beer.

References

[1] D programming language, see http://www.digitalmars.com/d/

[2] Don Clugston's π calculator, see http://trac.dsource.org/projects/ddl/browser/trunk/meta/demo/calcpi.d

[3] Don Clugston's decimaldigit and itoa, see http://trac.dsource.org/projects/ddl/browser/trunk/meta/conv.d

[4] Eric Niebler's Boost.Xpressive regular expression template library is at http://boost-sandbox.sourceforge.net/libs/xpressive/doc/html/index.html

[5] Eric Anderton's Regular Expression template library for D is at http://trac.dsource.org/projects/ddl/browser/trunk/meta/regex.d

Acknowledgements

I gratefully acknowledge the inspiration and assistance of Don Clugston, Eric Anderton and Matthew Wilson.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Tuples - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Tuples

A tuple is a sequence of elements. Those elements can be types, expressions, or aliases. The number and elements of a tuple are fixed at compile time; they cannot be changed at run time.

Tuples have characteristics of both structs and arrays. Like structs, the tuple elements can be of different types. Like arrays, the elements can be accessed via indexing.

So how does one construct a tuple? There isn't a specific tuple literal syntax. But since variadic template parameters create tuples, we can define a template to create one:

template Tuple(E...)
{
    alias E Tuple;
}

and it's used like:

Tuple!(int, long, float)	// create a tuple of 3 types
Tuple!(3, 7, 'c')		// create a tuple of 3 expressions
Tuple!(int, 8)			// create a tuple of a type and an expression

In order to symbolically refer to a tuple, use an alias:

alias Tuple!(float, float, 3) TP; // TP is now a tuple of two floats and 3

Tuples can be used as arguments to templates, and if so they are ‘flattened’ out into a list of arguments. This makes it straightforward to append a new element to an existing tuple or concatenate tuples:

alias Tuple!(TP, 8) TR;  // TR is now float,float,3,8
alias Tuple!(TP, TP) TS; // TS is float,float,3,float,float,3

Tuples share many characteristics with arrays. For starters, the number of elements in a tuple can be retrieved with the .length property:

TP.length	// evaluates to 3

Tuples can be indexed:

TP[1] f = TP[2];	// f is declared as a float and initialized to 3

and even sliced:

alias TP[0..length-1] TQ; // TQ is now the same as Tuple!(float, float)

Yes, length is defined within the [ ]s. There is one restriction: the indices for indexing and slicing must be evaluatable at compile time.

void foo(int i)
{
    TQ[i] x;		// error, i is not constant
}

These make it simple to produce the ‘head’ and ‘tail’ of a tuple. The head is just TP[0], the tail is TP[1 .. length]. Given the head and tail, mix with a little conditional compilation, and we can implement some classic recursive algorithms with templates. For example, this template returns a tuple consisting of the trailing type arguments TL with the first occurrence of the first type argument T removed:

template Erase(T, TL...)
{
    static if (TL.length == 0)
    // 0 length tuple, return self
        alias TL Erase;
    else static if (is(T == TL[0]))
    // match with first in tuple, return tail
        alias TL[1 .. length] Erase;
    else
    // no match, return head concatenated with recursive tail operation
        alias Tuple!(TL[0], Erase!(T, TL[1 .. length])) Erase;
}

Type Tuples

If a tuple's elements are solely types, it is called a TypeTuple (sometimes called a type list). Since function parameter lists are a list of types, a type tuple can be retrieved from them. One way is using an IsExpression:

int foo(int x, long y);

...
static if (is(foo P == function))
    alias P TP;
// TP is now the same as Tuple!(int, long)

This is generalized in the template std.traits.ParameterTypeTuple:

import std.traits;

...
alias ParameterTypeTuple!(foo) TP;	// TP is the tuple (int, long)

TypeTuples can be used to declare a function:

float bar(TP);	// same as float bar(int, long)

If implicit function template instantiation is being done, the type tuple representing the parameter types can be deduced:

int foo(int x, long y);

void Bar(R, P...)(R function(P))
{
    writefln("return type is ", typeid(R));
    writefln("parameter types are ", typeid(P));
}

...
Bar(&foo);

Prints:

return type is int
parameter types are (int,long)

Type deduction can be used to create a function that takes an arbitrary number and type of arguments:

void Abc(P...)(P p)
{
    writefln("parameter types are ", typeid(P));
}

Abc(3, 7L, 6.8);

Prints:

parameter types are (int,long,double)

For a more comprehensive treatment of this aspect, see Variadic Templates.

Expression Tuples

If a tuple's elements are solely expressions, it is called an ExpressionTuple. The Tuple template can be used to create one:

alias Tuple!(3, 7L, 6.8) ET;

...
writefln(ET);            // prints 376.8
writefln(ET[1]);         // prints 7
writefln(ET[1..length]); // prints 76.8

It can be used to create an array literal:

alias Tuple!(3, 7, 6) AT;

...
int[] a = [AT];		// same as [3,7,6]

The data fields of a struct or class can be turned into an expression tuple using the .tupleof property:

struct S { int x; long y; }

void foo(int a, long b)
{
    writefln(a, b);
}

...
S s;
s.x = 7;
s.y = 8;
foo(s.x, s.y);	// prints 78
foo(s.tupleof);	// prints 78
s.tupleof[1] = 9;
s.tupleof[0] = 10;
foo(s.tupleof); // prints 109
s.tupleof[2] = 11;  // error, no third field of S

A type tuple can be created from the data fields of a struct using typeof:

writefln(typeid(typeof(S.tupleof)));	// prints (int,long)

This is encapsulated in the template std.traits.FieldTypeTuple.

Looping

While the head-tail style of functional programming works with tuples, it's often more convenient to use a loop. The ForeachStatement can loop over either TypeTuples or ExpressionTuples.

alias Tuple!(int, long, float) TL;
foreach (i, T; TL)
    writefln("TL[%d] = ", i, typeid(T));

alias Tuple!(3, 7L, 6.8) ET;
foreach (i, E; ET)
    writefln("ET[%d] = ", i, E);

Prints:

TL[0] = int
TL[1] = long
TL[2] = float
ET[0] = 3
ET[1] = 7
ET[2] = 6.8

Tuple Declarations

A variable declared with a TypeTuple becomes an ExpressionTuple:

alias Tuple!(int, long) TL;

void foo(TL tl)
{
    writefln(tl, tl[1]);
}

foo(1, 6L);	// prints 166

Putting It All Together

These capabilities can be put together to implement a template that will encapsulate all the arguments to a function, and return a delegate that will call the function with those arguments.

import std.stdio;

R delegate() CurryAll(Dummy=void, R, U...)(R function(U) dg, U args)
{
    struct Foo
    {
    typeof(dg) dg_m;
    U args_m;

    R bar()
    {
        return dg_m(args_m);
    }
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    foreach (i, arg; args)
    f.args_m[i] = arg;
    return &f.bar;
}

R delegate() CurryAll(R, U...)(R delegate(U) dg, U args)
{
    struct Foo
    {
    typeof(dg) dg_m;
    U args_m;

    R bar()
    {
        return dg_m(args_m);
    }
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    foreach (i, arg; args)
    f.args_m[i] = arg;
    return &f.bar;
}

void main()
{
    static int plus(int x, int y, int z)
    {
    return x + y + z;
    }

    auto plus_two = CurryAll(&plus, 2, 3, 4);
    writefln("%d", plus_two());
    assert(plus_two() == 9);

    int minus(int x, int y, int z)
    {
    return x + y + z;
    }

    auto minus_two = CurryAll(&minus, 7, 8, 9);
    writefln("%d", minus_two());
    assert(minus_two() == 24);
}

The reason for the Dummy parameter is that one cannot overload two templates with the same parameter list. So we make them different by giving one a dummy parameter.

Future Directions

  • Return tuples from functions.
  • Use operators on tuples, like =, +=, etc.
  • Have tuple properties like .init which will apply the property to each of the tuple members.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Variadic Templates - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Variadic Templates

The problem statement is simple: write a function that takes an arbitrary number of values of arbitrary types, and print those values out one per line in a manner appropriate to the type. For example, the code:

print(7, 'a', 6.8);

should output:

7
'a'
6.8

We'll explore how this can be done in standard C++, followed by doing it using the proposed variadic template C++ extension. Then, we'll do it the various ways the D programming language makes possible.

C++ Solutions

The Standard C++ Solution

The straightforward way to do this in standard C++ is to use a series of function templates, one for each number of arguments:

#include <iostream>
using namespace::std;

void print()
{
}

template<class T1> void print(T1 a1)
{
    cout << a1 << endl;
}

template<class T1, class T2> void print(T1 a1, T2 a2)
{
    cout << a1 << endl;
    cout << a2 << endl;
}

template<class T1, class T2, class T3> void print(T1 a1, T2 a2, T3 a3)
{
    cout << a1 << endl;
    cout << a2 << endl;
    cout << a3 << endl;
}

... etc ...

This poses significant problems:

One, the function implementor must decide in advance what the maximum number of arguments the function will have. The implementor will usually err on the side of excess, and ten, or even twenty overloads of print() will be written. Yet inevitably, some user somewhere will require just one more argument. So this solution is never quite thoroughly right.

Two, the logic of the function template body must be cut and paste duplicated, then carefully modified, for every one of those function templates. If the logic needs to be adjusted, all of those function templates must receive the same adjustment, which is tedious and error prone.

Three, as is typical for function overloads, there is no obvious visual connection between them, they stand independently. This makes it more difficult to understand the code, especially if the implementor isn't careful to place them and format them in a consistent style.

Four, it leads to source code bloat which slows down compilation.

The C++ Extension Solution

Douglas Gregor has proposed a variadic template scheme [1] for C++ that solves these problems. The result looks like:

void print()
{
}

template<class T, class... U> void print(T a1, U... an)
{
    cout << a1 << newline;
    print(an...);
}

It uses recursive function template instantiation to pick off the arguments one by one. A specialization with no arguments ends the recursion. It's a neat and tidy solution, but with one glaring problem: it's a proposed extension, which means it isn't part of the C++ standard, may not get into the C++ standard in its current form, may not get into the standard in any form, and even if it does, it may be many, many years before the feature is commonly implemented.

D Programming Language Solutions

The D Look Ma No Templates Solution

It is not practical to solve this problem in C++ without using templates. In D, one can because D supports typesafe variadic function parameters.

import std.stdio;

void print(...)
{
    foreach (arg; _arguments)
    {
    writefx(stdout, (&arg)[0 .. 1], _argptr, 1);
    auto size = arg.tsize();
    _argptr += ((size + size_t.sizeof - 1) & ~(size_t.sizeof - 1));
    }
}

It isn't elegant or the most efficient, but it does work, and it is neatly encapsulated into a single function. (It relies on the predefined parameters _argptr and _arguments which give a pointer to the values and their types, respectively.)

Translating the Variadic C++ Solution into D

Variadic templates in D enable a straightforward translation of the proposed C++ variadic syntax:

void print()()
{
}

void print(T, A...)(T t, A a)
{
    writefln(t);
    print(a);
}

There are two function templates. The first provides the degenerate case of no arguments, and a terminus for the recursion of the second. The second has two arguments: t for the first value and a for the rest of the values. A... says the parameter is a tuple, and implicit function template instantiation will fill in A with the list of all the types following t. So, print(7, 'a', 6.8) will fill in int for T, and a tuple (char, double) for A. The parameter a becomes an expression tuple of the arguments.

The function works by printing the first parameter t, and then recursively calling itself with the remaining arguments a. The recursion terminates when there are no longer any arguments by calling print()().

The Static If Solution

It would be nice to encapsulate all the logic into a single function. One way to do that is by using static if's, which provide for conditional compilation:

void print(A...)(A a)
{
    static if (a.length)
    {
    writefln(a[0]);
    static if (a.length > 1)
        print(a[1 .. length]);
    }
}

Tuples can be manipulated much like arrays. So a.length resolves to the number of expressions in the tuple a. a[0] gives the first expression in the tuple. a[1 .. length] creates a new tuple by slicing the original tuple.

The Foreach Solution

But since tuples can be manipulated like arrays, we can use a foreach statement to 'loop' over the tuple's expressions:

void print(A...)(A a)
{
    foreach(t; a)
    writefln(t);
}

The end result is remarkably simple, self-contained, compact and efficient.

Acknowledgments

  1. Thanks to Andrei Alexandrescu for explaining to me how variadic templates need to work and why they are so important.
  2. Thanks to Douglas Gregor, Jaakko Jaervi, and Gary Powell for their inspirational work on C++ variadic templates.

References

  1. Variadic Templates N2080
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


D Slices - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

D Slices

by Steven Schveighoffer

One of the most pleasant features of the D language is its implementation of slices. Every time I use a programming language that isn't D, I find myself lamenting for D's slice syntax. Not only is it concise and efficient, but things "just work" when you are dealing with slices.

I'll go over some of the background and internals of D slices and arrays, and hopefully after reading this, you will have a clearer understanding of the proper ways to use D slices, as well as an idea of how fundamentally different they are than normal arrays!

An Overflowing Problem

In most languages, an array is a built-in type which manages its own data, and is passed around by reference. One refers to the entire thing as an "Array", and associates all the operations for the array (such as setting values, appending data for dynamic arrays, obtaining the length) to that type.

However, D takes its lineage from C, where an array is simply a chunk of contiguous data. In C, a reference to an array or array segment is as simple as a pointer (an explicit reference). C's arrays are distinctly unmanaged by the type that refers to them -- the pointer. The only operations supported are to retrieve and set data using an offset from the pointer.

For those of you unfamiliar with C, here are some examples of array usage in C (these also work in D):

arr[0] = 4; /* sets the first element of the array 'arr' to 4 */
x = arr[1]; /* retrieves the second element of the array 'arr' into x */

Everything else (length, appending, allocation, destruction) is left up to library functions and assumption/documentation. So what is so wrong with this concept? One of the largest problems with C arrays is the ability to access any data via the pointer, even data that doesn't belong to the array. You can even use negative indexes! Not to mention that the array uses the exact same type as a pointer to a single item. When you get a pointer as a parameter to a function, that could be an array, or it could be just a pointer to a single item. Cue buffer overflow attacks. You can read more about this in Walter Bright's article, "C's biggest mistake"

Introducing Slices

So how does D improve things? In many ways, D's arrays are similar to C's arrays. In fact, D supports C's array syntax using pointers. However, D provides a new type that builds on C array syntax called a slice. A slice is a segment of an array (dynamic or otherwise) that tracks both the pointer and the length of the segment. With the combined protection of having the length of the data, and the garbage collector to manage the memory backing the data, slices are an extremely powerful, dynamic concept that is safe from most memory corruption issues. In addition, D slices support extending with simple functions which take a slice as the first parameter. This allows one to add any functionality you want to a built-in type via properties or methods. With D slices, one can write high-performance code with elegant and concise syntax that is awkward or inefficient in almost any other language.

Let's see some D slices in action:

import std.stdio;

void main()
{
    int[] a;             // a is a slice

    a = new int[5];      // allocate a dynamic array of integers that has at least 5
                         // elements, and give me a slice to the first 5.  Note
                         // that all data in D is default assigned, int's are
                         // defaulted to 0, so this array contains five 0's

    int[] b = a[0..2];   // This is a 'slicing' operation.  b now refers to the
                         // first two elements of a.  Note that D uses open interval
                         // for the upper limit, so a[2] is not included in b.

    int[] c = a[$-2..$]; // c refers to the last two elements of a
                         // ($ stands for length inside a slice or index operation).

    c[0] = 4;            // this also assigns a[3]
    c[1] = 5;            // this also assigns a[4]

    b[] = c[];           // assign the first two elements of a[] to the value from
                         // the last two elements (4, 5).

    writeln(a);          // prints "[4, 5, 0, 4, 5]"

    int[5] d;            // d is a fixed sized array, allocated on the stack
    b = d[0..2];         // slices can point at fixed sized arrays too!
}

You may notice something puzzling about the description of the allocation of the array: "allocate a dynamic array of integers that has at least 5 elements, and give me a slice to the first 5." Why isn't it just "allocate a dynamic array of 5 elements"? Even experienced D coders have trouble with D's array concepts sometimes, and for quite good reason. D's slices are not proper dynamic array types (at least not under the hood) even though they appear to be. What they do is provide a safe and easy interface to arrays of any type (dynamic or otherwise). So let's discuss probably the most common misconception of D slices.

Who's Responsible?

A slice in D seems like a dynamic array in almost all aspects of the concept -- when passed without adornments, the data referred to is passed by reference, and it supports all the properties and functions one would expect a dynamic array type to support. But there is one very important difference. A slice does not own the array, it references the array. That is, the slice is not responsible for allocation or deallocation of its data. The responsible party for managing a dynamic array's memory is the D runtime.

So where is the true dynamic array type in D? It's hidden by the runtime, and in fact, has no formal type. Slices are good enough, and as it turns out, the runtime is smart enough about what you want to do with the data, that you almost never notice dynamic arrays are missing as a full-fledged type. In fact, most D coders consider the D slice to be the dynamic array type -- it's even listed as a dynamic array type in the spec! The lack of ownership is very subtle and easy to miss.

Another consequence of this is that the length is not an array property, it's a slice property. This means the length field is not necessarily the length of the array, it's the length of the slice. This can be confusing to newcomers to the language. For instance, this code has a large flaw in it:

import std.stdio;

void shrinkTo2(int[] arr)
{
    if(arr.length > 2)
        arr.length = 2;
}

void main()
{
   int[] arr = new int[5];
   arr.shrinkTo2();     // note the ability to call shrinkTo2 as a method
   writeln(arr.length); // outputs 5
}

This might look like you changed the passed arr's length to 2, but it actually did not affect anything (as is proven by the output from writeln). This is because even though the data is passed by reference, the actual pointer and length are passed by value. Many languages have an array type whose properties are all passed by reference. Notably, C# and Java arrays are actually fully referenced Objects. C++'s vector either passes both its data and properties by reference or by value.

To fix this problem, you can do one of two things. Either you explicitly pass the slice by reference via the ref keyword, or you return the resulting slice to be reassigned. For example, here is how the signature would look if the slice is passed by reference:

void shrinkTo2(ref int[] arr)

Let's say you make this change, what happens to the data beyond the second element? In D, since slices don't own the data, it's still there, managed by the nebulous dynamic array type. The reason is fundamental: some other slice may still be referencing that data! The fact that no single slice is the true owner of the data means no single slice can make any assumptions about what else references the array data.

What happens when no slices reference that data? Enter D's garbage collector. The garbage collector is responsible for cleaning up dynamic arrays that no longer are referenced by any slices. In fact, it is the garbage collector that makes much of D's slice usage possible. You can slice and serve up segments of dynamic arrays, and never have to worry that you are leaking memory, clobbering other slices, or worry about managing the lifetime of the array.

A Slice You Can Append On

D's slices support appending more data to the end of the slice, much like a true dynamic array type. The language has a specific operator used for concatenation and appending, the tilde (~). Here are some operations that append and concatenate arrays:

int[] a;     // an empty slice references no data, but still can be appended to
a ~= 1;      // append some integers, this automatically allocates a new
a ~= 2;      // array to hold the elements.

a ~= [3, 4]; // append another array (this time, an array literal)
a = a ~ a;   // concatenate a with itself, a is now [1, 2, 3, 4, 1, 2, 3, 4]

int[5] b;    // a fixed-size array on the stack
a = b[1..$]; // a is a slice of b
a ~= 5;      // since a was pointing to stack data, appending always reallocates,
             // but works!

Anyone who cares about performance will wonder what happens when you append the four elements. The slice does not own its data, so how does one avoid reallocating a new array on each append operation? One of the main requirements of D slices are that they are efficient. Otherwise, coders would not use them. D has solved this problem in a way that is virtually transparent to the programmer, and this is one of the reasons slices seem more like true dynamic arrays.

How it Works

Remember before when we allocated a new array, I said allocate a dynamic array of at least n elements and give me a slice? Here is where the runtime earns its keep. The allocator only allocates blocks in powers of 2 up to a page of data (in 32-bit x86, a page of data is 4096 bytes), or in multiples of pages. So when you allocate an array, you can easily get a block that's larger than requested. For instance, allocating a block of five 32 bit integers (which consumes 20 bytes) provides you a block of 32 bytes. This leaves space for 3 more integers.

It's clearly possible to append more integers into the array without reallocating, but the trick is to prevent "stomping" on data that is valid and in use. Remember, the slice doesn't know what other slices refer to that data, or really where it is in the array (it could be a segment at the beginning or the middle). To make the whole thing work, the runtime stores the number of used bytes inside the block itself (a minor drawback is that the usable space in the block is not as big as it could be. In our example, for instance, we can truly only store 7 integers before needing to reallocate into another block).

When we request the runtime to append to a slice, it first checks to see that both the block is appendable (which means the used field is valid), and the slice ends at the same point valid data ends (it is not important where the slice begins). The runtime then checks to see if the new data will fit into the unused block space. If all of these checks pass, the data is written into the array block, and the stored used field is updated to include the new data. If any of these checks fail, a new array block is allocated that will hold the existing and new data, which is then populated with all the data. What happens to the old block? If there were other slices referencing it, it stays in place without being changed. If nothing else is referencing it, it becomes garbage and is reclaimed on the next collection cycle. This allows you to safely reallocate one slice without invalidating any others. This is a huge departure from C/C++, where reallocating an array, or appending to a vector can invalidate other references to that data (pointers or iterators).

The result is an append operation which is not only efficient, but universally handy. Whenever you want to append a slice, you can, without worry about performance or corruption issues. You don't even have to worry about whether a slice's data is heap allocated, stack allocated, in ROM, or even if it's null. The append operation always succeeds (given you have enough memory), and the runtime takes care of all the dirty work in the background.

Determinism

There is one caveat with slice appending that can bite inexperienced, and even experienced D coders: the apparent non-deterministic behavior of appending.

Let's say we have a function which is passed a buffer, and writes some number of A's to the buffer (appending if necessary), returning the filled buffer:

import std.stdio;

char[] fillAs(char[] buf, size_t num)
{
   if(buf.length < num)
      buf.length = num; // increase buffer length to be able to hold the A's
   buf[0..num] = 'A';   // assign A to all the elements
   return buf[0..num];  // return the result
}

What's wrong with the fillAs function? Nothing really, but what happens if increasing the length forces the buffer to be reallocated? In that case, the buffer passed in is not overwritten with A's, only the reallocated buffer is. This can be surprising if you were expecting to continue to use the same buffer in further operations, or if you expected the original buffer to be filled with A's. The end result, depending on whether the block referenced by buf[] can be appended in place, is the caller's slice might be overwritten with A's, or it might not be.

// continued example...
void main()
{
   char[] str = new char[10];  // Note, the block capacity allocated for this is
                               // 15 elements
   str[] = 'B';
   fillAs(str, 20);            // buffer must be reallocated (20 > 15)
   writeln(str);               // "BBBBBBBBBB"
   fillAs(str, 12);            // buffer can be extended in place (12 <= 15)!
   writeln(str);               // "AAAAAAAAAA";
}

If you give this some thought, you should come to the conclusion that such a situation is unavoidable without costly copy-on-append semantics -- the system cannot keep track of every slice that references the data, and you have to put the new data somewhere. However, there are a couple options we have to mitigate the problem:

  1. Re-assign the slice to the return value of the function. Note that the most important result of this function is the return value, not whether the buffer was used or not.
  2. Don't use the passed in buffer again. If you don't use the source slice again, then you can't experience any issues with it.

As the function author, there are some things we can do to avoid causing these problems. It's important to note that the only time this situation can occur is when the function appends to, or increases the length of, a passed in slice and then writes data to the original portion of the slice. Avoiding this specific situation where possible can reduce the perception of non-determinism. Later we will discuss some properties you can use to predict how the runtime will affect your slice. It is a good idea to note in the documentation how the passed in slice might or might not be overwritten.

A final option is to use ref to make sure the source slice is updated. This is sometimes not an option as a slice can easily be an rvalue (input only). However, this does not fix the problem for any aliases to the same data elsewhere.

Caching

One of the issues with appending to a slice is that the operation is quick, but not quick enough. Every time we append, we need to fetch the metadata for the block (its starting address, size, and used data). Doing this means an O(lg(n)) lookup in the GC's memory pool for every append (not to mention acquiring the global GC lock). However, what we want is amortized constant appending. To achieve this lofty goal, we employ a caching technique that is, as far as I know, unique to D.

Since D has the concept of default thread local storage, the type system can tell us whether heap data is local to the thread (and most data is), or shared amongst all threads. Using this knowledge, we can achieve lock-free caching of this metadata for thread-local appends, with one cache per thread. The cache stores the most recent N lookups of metadata, giving us quick access to whether a slice can be appended.

Slice Members and the Appender

With D slices having such interesting behavior, there is a need sometimes to be able to predict the behavior of slices and appending. To that end, several properties and methods have been added to the slice.

size_t reserve(size_t n): Reserves n elements for appending to a slice. If a slice can already be appended in place, and there is already space in the array for at least n elements (n represents both existing slice elements and appendable space), nothing is modified. It returns the resulting capacity.

int[] slice;
slice.reserve(50);
foreach(int i; 0..50)
   slice ~= i;        // does not reallocate

size_t capacity: A property which gives you the number of elements the slice can hold via appending. If the slice cannot be appended in place, this returns 0. Note that capacity (if non-zero) includes the current slice elements.

int[] slice = new int[5];
assert(slice.capacity == 7);  // includes the 5 pre-allocated elements
int[] slice2 = slice;
slice.length = 6;
assert(slice.capacity == 7);  // appending in place doesn't change the capacity.
assert(slice2.capacity == 0); // cannot append slice2 because it would stomp on
                              // slice's 6th element

assumeSafeAppend(): This method forces the runtime to assume it is safe to append a slice. Essentially this adjusts the used field of the array to end at the same spot the slice ends.

int[] slice = new int[5];
slice = slice[0..2];
assert(slice.capacity == 0); // not safe to append, there is other valid data in the block.
slice.assumeSafeAppend();
assert(slice.capacity == 7); // force the used data to 2 elements

If D slices' append performance just isn't up to snuff for your performance requirements, there is another alternative. The std.array.Appender type will append data to an array as fast as possible, without any need to look up metadata from the runtime. Appender also supports the output range idiom via an append operation (normal slices only support the output range by overwriting their own data).

Conclusion

Whether you are a seasoned programmer or a novice, the array and slice concepts in D provide an extremely rich feature set that allows for almost anything you would want to do with an array type. With a large focus on performance and usability, the D slice type is one of those things that you don't notice how great it is until you work with another language that doesn't have it.

Thanks to David Gileadi, Andrej Mitrovic, Jesse Phillips, Alex Dovhal, Johann !MacDonagh, and Jonathan Davis for their reviews and suggestions for this article

© 2011-2012 by Steven Schveighoffer
Creative Commons License
This work is licensed under a Creative Commons Attribution-NoDerivs 3.0 Unported License.
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Template Constraints - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Template Constraints

Templates are normally overloaded and matched based on the template arguments being matched to the template parameters. The template parameters can specify specializations, so that the template argument must match particular type patterns. Similarly, template value arguments can be constrained to match particular types.

But this has its limitations. Many times there are arbitrarily more complex criteria for what should be accepted by the template. This can be used to:

  • more finely discriminate about which template gets instantiated for given arguments
  • provides better self-documentation about what characteristics template parameters must have
  • can provide better diagnostics when arguments don't match, rather than an obscure error message based on the irrelevant (to the user) internal details of the template implementation

Constraints address this by simply providing an expression that must evaluate at compile time to true after the arguments are matched to the parameters. If it is true, then that template is a valid match for the arguments, if not, then it is not and is passed over during overload matching.

The constraint expression follows the template declaration and the if keyword:

template Foo(int N)
        if (N & 1)
{
    ...
}

which constrains the template Foo to match only if its argument is an odd integer. Arbitrarily complex criteria can be used, as long as it can be computed at compile time. For example, here's a template that only accepts prime numbers:

bool isprime(int n)
{
    if (n < 1 || (n & 1) == 0)
    return false;
    if (n > 3)
    {
    for (auto i = 3; i * i < n; i += 2)
    {
        if ((n % i) == 0)
        return false;
    }
    }
    return true;
}

template Foo(int N)
    if (isprime(N))
{
    ...
}

Foo!(5)    // ok, 5 is prime
Foo!(6)    // no match for Foo

Type constraints can be complex, too. For example, a template Bar that will accept any floating point type using the traditional type specializations:

template Bar(T:float)
{
   ...
}
template Bar(T:double)
{
   ...
}
template Bar(T:real)
{
   ...
}

and the template implementation body must be duplicated three times. But with constraints, this can be specified with one template:

template Bar(T)
    if (is(T == float) || is(T == double) || is(T == real))
{
   ...
}

This can be simplified by using the isFloatingPoint template in library module std.traits:

import std.traits;
template Bar(T)
    if (isFloatingPoint!(T))
{
   ...
}

Characteristics of types can be tested, such as if a type can be added:

// Returns true if instances of type T can be added
template isAddable(T)
{   // Works by attempting to add two instances of type T
    const isAddable = __traits(compiles, (T t) { return t + t; });
}

int Foo(T)(T t)
    if (isAddable!(T))
{
    return 3;
}

struct S
{
    void opAdd(S s) { }   // an addable struct type
}

void main()
{
    Foo(4);   // succeeds
    S s;
    Foo(s);   // succeeds
    Foo("a"); // fails to match
}

Since any expression that can be computed at compile time is allowed as a constraint, constraints can be composed:

int Foo(T)(T t)
    if (isAddable!(T) && isMultipliable!(T))
{
    return 3;
}

A more complex constraint can specify a list of operations that must be doable with the type, such as isStack which specifies the constraints that a stack type must have:

template isStack(T)
{
    const isStack =
        __traits(compiles,
          (T t)
          {   T.value_type v = top(t);
              push(t, v);
              pop(t);
              if (empty(t)) { }
          });
}

template Foo(T)
    if (isStack!(T))
{
    ...
}

and constraints can deal with multiple parameters:

template Foo(T, int N)
    if (isAddable!(T) && isprime(N))
{
    ...
}

Overloading based on Constraints

Given a list of overloaded templates with the same name, constraints act as a yes/no filter to determine the list of candidates for a match. Overloading based on constraints can thus be achieved by setting up constraint expressions that are mutually exclusive. For example, overloading template Foo so that one takes odd integers and the other even:

template Foo(int N) if (N & 1)    { ... } // A
template Foo(int N) if (!(N & 1)) { ... } // B
...
Foo!(3)    // instantiates A
Foo!(64)   // instantiates B

Constraints are not involved with determining which template is more specialized than another.

void foo(T, int N)()        if (N & 1) { ... } // A
void foo(T : int, int N)()  if (N > 3) { ... } // B
...
foo!(int, 7)();   // picks B, more specialized
foo!(int, 1)();   // picks A, as it fails B's constraint
foo!("a", 7)();   // picks A
foo!("a", 4)();   // error, no match

References

  • Concepts (Revision 1) by Douglas Gregor and Bjarne Stroustrup
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


D's Contract Programming vs C++'s - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

D's Contract Programming vs C++'s

Many people have written me saying that D's Contract Programming (DbC) does not add anything that C++ does not already support. They go on to illustrate their point with a technique for doing DbC in C++.

It makes sense to review what DbC is, how it is done in D, and stack that up with what each of the various C++ DbC techniques can do.

Digital Mars C++ adds extensions to C++ to support DbC, but they are not covered here because they are not part of standard C++ and are not supported by any other C++ compiler.

Contract Programming in D

This is more fully documented in the D Contract Programming document. To sum up, DbC in D has the following characteristics:
  1. The assert is the basic contract.
  2. When an assert contract fails, it throws an exception. Such exceptions can be caught and handled, or allowed to terminate the program.
  3. Classes can have class invariants which are checked upon entry and exit of each public class member function, the exit of each constructor, and the entry of the destructor.
  4. Assert contracts on object references check the class invariant for that object.
  5. Class invariants are inherited, that means that a derived class invariant will implicitly call the base class invariant.
  6. Functions can have preconditions and postconditions.
  7. For member functions in a class inheritance hierarchy, the precondition of a derived class function are OR'd together with the preconditions of all the functions it overrides. The postconditions are AND'd together.
  8. By throwing a compiler switch, DbC code can be enabled or can be withdrawn from the compiled code.
  9. Code works semantically the same with or without DbC checking enabled.

Contract Programming in C++

The assert Macro

C++ does have the basic assert macro, which tests its argument and if it fails, aborts the program. assert can be turned on and off with the NDEBUG macro.

assert does not know anything about class invariants, and does not throw an exception when it fails. It just aborts the program after writing a message. assert relies on a macro text preprocessor to work.

assert is where explicit support for DbC in Standard C++ begins and ends.

Class Invariants

Consider a class invariant in D:
class A
{
    invariant() { ...contracts... }

    this() { ... }	// constructor
    ~this() { ... }	// destructor

    void foo() { ... }	// public member function
}

class B : A
{
    invariant() { ...contracts... }
    ...
}
To accomplish the equivalent in C++ (thanks to Bob Bell for providing this):
template
inline void check_invariant(T& iX)
{
#ifdef DBC
    iX.invariant();
#endif
}

// A.h:

class A {
    public:
#ifdef DBG
       virtual void invariant() { ...contracts... }
#endif
       void foo();
};

// A.cpp:

void A::foo()
{
    check_invariant(*this);
    ...
    check_invariant(*this);
}

// B.h:

#include "A.h"

class B : public A {
    public:
#ifdef DBG
    virtual void invariant()
    {   ...contracts...
       A::invariant();
    }
#endif
       void bar();
};

// B.cpp:

void B::barG()
{
    check_invariant(*this);
    ...
    check_invariant(*this);
}
There's an additional complication with A::foo(). Upon every normal exit from the function, the invariant() should be called. This means that code that looks like:
int A::foo()
{
    ...
    if (...)
    return bar();
    return 3;
}
would need to be written as:
int A::foo()
{
    int result;
    check_invariant(*this);
    ...
    if (...)
    {
    result = bar();
    check_invariant(*this);
    return result;
    }
    check_invariant(*this);
    return 3;
}
Or recode the function so it has a single exit point. One possibility to mitigate this is to use RAII techniques:
int A::foo()
{
#if DBC
    struct Sentry {
       Sentry(A& iA) : mA(iA) { check_invariants(iA); }
       ~Sentry() { check_invariants(mA); }
       A& mA;
    } sentry(*this);
#endif
    ...
    if (...)
    return bar();
    return 3;
}
The #if DBC is still there because some compilers may not optimize the whole thing away if check_invariants compiles to nothing.

Preconditions and Postconditions

Consider the following in D:
void foo()
    in { ...preconditions... }
    out { ...postconditions... }
    body
    {
    ...implementation...
    }
This is nicely handled in C++ with the nested Sentry struct:
void foo()
{
    struct Sentry
    {   Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
    ...implementation...
}
If the preconditions and postconditions consist of nothing more than assert macros, the whole doesn't need to be wrapped in a #ifdef pair, since a good C++ compiler will optimize the whole thing away if the asserts are turned off.

But suppose foo() sorts an array, and the postcondition needs to walk the array and verify that it really is sorted. Now the shebang needs to be wrapped in #ifdef:

void foo()
{
#ifdef DBC
    struct Sentry
    {   Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
#endif
    ...implementation...
}
(One can make use of the C++ rule that templates are only instantiated when used can be used to avoid the #ifdef, by putting the conditions into a template function referenced by the assert.)

Let's add a return value to foo() that needs to be checked in the postconditions. In D:

int foo()
    in { ...preconditions... }
    out (result) { ...postconditions... }
    body
    {
    ...implementation...
    if (...)
        return bar();
    return 3;
    }
In C++:
int foo()
{
#ifdef DBC
    struct Sentry
    {   int result;
    Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
#endif
    ...implementation...
    if (...)
    {   int i = bar();
#ifdef DBC
    sentry.result = i;
#endif
    return i;
    }
#ifdef DBC
    sentry.result = 3;
#endif
    return 3;
}
Now add a couple parameters to foo(). In D:
int foo(int a, int b)
    in { ...preconditions... }
    out (result) { ...postconditions... }
    body
    {
    ...implementation...
    if (...)
        return bar();
    return 3;
    }
In C++:
int foo(int a, int b)
{
#ifdef DBC
    struct Sentry
    {   int a, b;
    int result;
    Sentry(int a, int b)
    {   this->a = a;
        this->b = b;
        ...preconditions...
    }
    ~Sentry() { ...postconditions... }
    } sentry(a,b);
#endif
    ...implementation...
    if (...)
    {   int i = bar();
#ifdef DBC
        sentry.result = i;
#endif
        return i;
    }
#ifdef DBC
    sentry.result = 3;
#endif
    return 3;
}

Preconditions and Postconditions for Member Functions

Consider the use of preconditions and postconditions for a polymorphic function in D:
class A
{
    void foo()
    in { ...Apreconditions... }
    out { ...Apostconditions... }
    body
    {
        ...implementation...
    }
}

class B : A
{
    void foo()
    in { ...Bpreconditions... }
    out { ...Bpostconditions... }
    body
    {
        ...implementation...
    }
}
The semantics for a call to B.foo() are:
  • Either Apreconditions or Bpreconditions must be satisfied.
  • Both Apostconditions and Bpostconditions must be satisfied.
Let's get this to work in C++:
class A
{
protected:
    #if DBC
    int foo_preconditions() { ...Apreconditions... }
    void foo_postconditions() { ...Apostconditions... }
    #else
    int foo_preconditions() { return 1; }
    void foo_postconditions() { }
    #endif

    void foo_internal()
    {
    ...implementation...
    }

public:
    virtual void foo()
    {
    foo_preconditions();
    foo_internal();
    foo_postconditions();
    }
};

class B : A
{
protected:
    #if DBC
    int foo_preconditions() { ...Bpreconditions... }
    void foo_postconditions() { ...Bpostconditions... }
    #else
    int foo_preconditions() { return 1; }
    void foo_postconditions() { }
    #endif

    void foo_internal()
    {
    ...implementation...
    }

public:
    virtual void foo()
    {
    assert(foo_preconditions() || A::foo_preconditions());
    foo_internal();
    A::foo_postconditions();
    foo_postconditions();
    }
};
Something interesting has happened here. The preconditions can no longer be done using assert, since the results need to be OR'd together. I'll leave as a reader exercise adding in a class invariant, function return values for foo(), and parameters for foo().

Conclusion

These C++ techniques can work up to a point. But, aside from assert, they are not standardized and so will vary from project to project. Furthermore, they require much tedious adhesion to a particular convention, and add significant clutter to the code. Perhaps that's why it's rarely seen in practice.

By adding support for DbC into the language, D offers an easy way to use DbC and get it right. Being in the language standardizes the way it will be used from project to project.

References

Chapter C.11 introduces the theory and rationale of Contract Programming in Object-Oriented Software Construction
Bertrand Meyer, Prentice Hall

Chapters 24.3.7.1 to 24.3.7.3 discuss Contract Programming in C++ in The C++ Programming Language Special Edition
Bjarne Stroustrup, Addison-Wesley

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:06 2013


Migrating D1 Code to D2 - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Migrating D1 Code to D2

There are many changes to the D programming language that affect migrating source code from D1 to D2. This is an outline of changes to look for and a guide to how to modify the code. See D 2.0 Enhancements for a complete list of changes to the language.

This document is incomplete.

  • Core Language
    • New Keywords
    • Global Variables
    • Static Arrays are now Value Types
    • String Literals are Immutable
  • Phobos Library

New Keywords

D2 adds the following keywords: pure, nothrow, shared, and immutable. Any use of them in D1 code must be renamed. Any variable names starting with two underscores should be renamed.

Global Variables

Global variables are now, by default, stored in thread local storage. To put them back in global storage, use the __gshared storage class:

int foo = 7; // D1 code
__gshared int foo = 7; // D2 equivalent

Carefully consider whether or not those variables actually should go into thread local storage, rather than being implicitly shared among all threads.

Static Arrays are now Value Types

In D1, a static array function parameter is passed by reference, meaning a pointer to the start of the static array is passed as an argument. This means that any changes to the array contents made by the function will be visible to the function's caller. In D2, a copy of the whole static array is passed as an argument. Changes to the array contents by the function are not visible to the function's caller, as it is a separate copy.

To migrate, add the keyword ref to the parameter declaration:

void foo(int[3] array);      // D1 code
void foo(ref int[3] array);  // D2 equivalent

String Literals are Immutable

String literals in D1 have type char[], but in D2 they have type immutable(char)[], which is aliased for convenience under the name string. To migrate usually involves doing a global search replace:

from | to
char[] | string
wchar[] | wstring
dchar[] | dstring

This will take care of most of the issues. For the rest, where mutable strings are desired, there will be some work necessary.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Deprecated Features - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Deprecated Features

Sometimes it becomes clear that a feature is just a bad idea. These are called deprecated features and once they are judged to merit removal from the language, they follow a procedure in order to allow plenty of time for users to adjust to the change.

Deprecated Features
Feature | Spec | Warn | Dep | Error | Gone
Cast T[] to integral type | ? | N/A | 2.060 | 2.061 |
Base Class Protection | 2.058 | N/A | 2.058 |  |
Using length in index expressions | ? | N/A | 2.041 | 2.061 |
typedef | 2.057 | N/A | 2.057 |  |
Variable shadowing inside functions | ? | N/A | 0.161 | 2.061 |
invariant as an alias for immutable | 2.057 | N/A | 2.057 |  |
Using * to dereference arrays | ? | N/A | 2.057 |  |
Removing an item from an associative array with delete | ? | N/A | 0.127 | 2.061 |
.offset property | ? | N/A | 0.107 | 2.061 |
.size property | ? | N/A | 0.107 | 0.107 | 2.061
Escape string literals | ? | N/A | 2.026 | 2.061 |
Lower case 'l' suffix for integer literals | ? | N/A | 1.054 | 0.174 | 2.061
Octal literals | 2.054 | N/A | 2.053 |  |
Upper case 'I' suffix for imaginary literals | ? | N/A | 0.154 | 2.061 |
HTML source files | ? | N/A | 2.013 | N/A | 2.061
.typeinfo property | ? | N/A | 0.093 | 2.061 |
C-style function pointers | ? | N/A | 2.050 |  |
C-style array pointers | ? | N/A | 2.050 |  |
if (v; e) | ? | N/A | 0.149 | 2.061 |
volatile | 2.013 | N/A | 2.013 |  |
Non-final switch statements without a default case | 2.054 | N/A | 2.054 |  |
Hiding base class functions | 2.054 | N/A | 2.054 |  |
Windows 3.x and Windows 9x support | 2.058 | N/A | N/A | N/A | 2.058
.min property for floating point types | N/A | 2.061 |  |  |
imaginary and complex types | future |  |  |  |
floating point NCEG operators | future |  |  |  |
.sort and .reverse properties for arrays | future |  |  |  |
delete | future |  |  |  |
overriding without override | future |  |  |  |
scope for allocating classes on the stack | future |  |  |  |
Spec
Removal from the Specification
Warn
The compiler emits a warning if the feature is used
Dep
The compiler issues an error if not compiled with the -d switch
Error
It is an error to use the feature
Gone
The feature is completely gone

Cast T[] to integral type

At some point in time you could do:
ulong u = cast(ulong)[1,2];
To get the length of the array.

Corrective Action

Use the .length property instead.

Rationale

Using a cast to get the length of an array is just confusing.

Base Class Protection

Base class protections are things like:
class A : protected B {
   ...
}

Corrective Action

Delete the protection attribute keyword from in front of the base class and base interfaces.

Rationale

With D's module system, it doesn't seem to serve any useful purpose, and has never worked correctly.

Using length in index expressions

When used inside an indexing or slicing expression, length is rewritten to be the length of the array being sliced.
auto a = new int[5];
a = a[0..length-1];

Corrective Action

Replace length with the equivalent '$'

Rationale

The implicitly defined length variable shadows existing declarations, and is less concise than the alternative.

typedef

typedef can be used to construct a strongly-typed alias of a type.
typedef int myint;
static assert(!is(myint == int));

Corrective Action

Replace use of typedef with alias or use std.typecons.Typedef.

Rationale

typedef is not flexible enough to cover all use cases. This is better done with a library solution.

Variable shadowing inside functions

Variable shadowing is when a variable in an inner scope has the same name as a variable in an enclosing scope.
void myFun()
{
    int var;
    if (x)
    {
        int var;
        var = 3; // which var was meant?
    }
}

Corrective Action

Rename shadowing variables so they don't conflict.

Rationale

Variable shadowing can introduce hard to find bugs where the wrong variable is modified.

invariant as an alias for immutable

The invariant storage class and type modifier is an alias for immutable.
static assert(is(invariant(int) == immutable(int)));

Corrective Action

Replace all uses of invariant as a storage class or type modifier with immutable. The invariant() syntax for struct and class invariants is still supported.

Rationale

The alias is unnecessary.

Using * to dereference arrays

D array variables can be dereferenced to get the first element, much like pointers.
int[] arr = [1, 2, 3];
assert(*arr == 1);

Corrective Action

Use indexing syntax to access first member.

int[] arr = [1, 2, 3];
assert(arr[0] == 1);

Rationale

D arrays are not pointers.

Removing an item from an associative array with delete

delete can be used to remove an item from an associative array.
int[int] aa = [1 : 2];
delete aa[1];
assert(1 !in aa);

Corrective Action

Use .remove instead.

int[int] aa = [1 : 2];
aa.remove(1);
assert(1 !in aa);

Rationale

The delete syntax is confusing and conflicts with the normal delete syntax.

.offset property

The .offset property can be used to get member offset information.
struct S { int a, b; }
static assert(S.b.offset == 4);

Corrective Action

Use .offsetof instead

struct S { int a, b; }
static assert(S.b.offsetof == 4);

Rationale

The .offset syntax has been superseded by .offsetof

.size property

The .size property can be used to get type size information
struct S { int a, b; }
static assert(S.size == 8);

Corrective Action

Use .sizeof instead

struct S { int a, b; }
static assert(S.sizeof == 8);

Rationale

The .size syntax has been superseded by .sizeof

Escape string literals

Escape string literals can be used to describe characters using escape sequences.
string x = "hello" ~ \n;

Corrective Action

Put escape sequences inside a regular string literal.

string x = "hello\n";

Rationale

Escape string literals are unintuitive and unnecessary.

Lower case 'l' suffix for integer literals

Lower case 'l' is an alternative suffix to denote 64 bit integer literals.
auto x = 123l;

Corrective Action

Use the upper case 'L' suffix.

auto x = 123L;

Rationale

The lower case suffix is easily confused with the digit '1'.

Octal literals

Octal literals can be used to enter literals in base 8.
auto x = 0123;

Corrective Action

Use the octal!num template.

auto x = octal!123;

Rationale

The use of a leading zero is confusing, as 0123 != 123.

Upper case 'I' suffix for imaginary literals

The 'I' suffix can be used to denote imaginary floating point values.
auto x = 1.234I;

Corrective Action

Use the lower case 'i' suffix.

auto x = 1.234i;

Rationale

The 'I' suffix is easily confused with the digit '1'.

HTML source files

The D compiler can parse html files by ignoring everything not contained in <code></code> tags.
<html>
<code>
    ... source ...
</code>
</html>

Corrective Action

Extract code to regular source files.

Rationale

This has been replaced for documentation by the introduction of ddoc

.typeinfo property

The .typeinfo property can be used to get the associated TypeInfo class.
T.typeinfo

Corrective Action

Use typeid() instead

typeid(T)

Rationale

The .typeinfo syntax has been superseded by typeid()

C-style function pointers

C-style function pointers can be used in D.
alias void(*fptr)(int, long);

Corrective Action

Replace with D-style function pointers.

alias void function(int, long) fptr;

Rationale

The D syntax is much cleaner and easier to use.

C-style array pointers

C-style array pointers can be used in D.
alias float *arrayptr[10][15];

Corrective Action

Replace with D-style array pointers.

alias float[15][10]* arrayptr;

Rationale

The D syntax is much cleaner and easier to use.

if (v; e)

This syntax can be used to declare a variable in an if statement condition.
if (v; calculateAndReturnPointer()) { ... }

Corrective Action

Replace with an auto declaration.

if (auto v = calculateAndReturnPointer()) { ... }

Rationale

The syntax is clearer with auto.

volatile

volatile can be used to mark statement, in order to prevent some compiler optimizations.
volatile
{
    ... do something involving ghared variables ...
}

Corrective Action

Convert the code to use synchronized statements instead.

Rationale

volatile statements are a misfeature.

Non-final switch statements without a default case

Switch statements can be declared without a default case, and the compiler automatically adds one.
switch(a)
{
case 1:
    break;
case 2:
    break;
// the compiler adds
// default:
//     throw new SwitchError();
}

Corrective Action

Add the default case manually.

switch(a)
{
case 1:
    break;
case 2:
    break;
default:
    assert(0);
}

Rationale

Missing default cases can hide bugs, and making the default case explicit should be mandatory.

Hiding base class functions

Declaration functions in a derived class that can be called with the same arguments as a function in a base class, but do not override that function causes the base class function to be hidden.
class A
{
    void fun(int x) {}
}
class B : A
{
    void fun(long x) {}
}

Corrective Action

Add the function to the base class, or use an alias to bring the base class overload into the derived class.

class A
{
    void fun(int x) {}
    void fun(long x) {} // this fixes it
}
class B : A
{
    void fun(long x) {}
    alias A.fun fun; // so does this
}

Rationale

This is an error that is already detected at runtime, and is being extended to compile time.

Windows 3.x and Windows 9x support

There is some code in Phobos for Windows 3.x/9x support.

Corrective Action

Upgrade Windows or switch to another supported OS.

Rationale

Supporting such outdated and rarely used OS-es isn't worth the trouble.

.min property for floating point types

Floating point types have the .min property to access the smallest value.
enum m = real.min;

Corrective Action

Replace with .min_normal

enum m = real.min_normal;

Rationale

The name min_normal is more accurate, as .min does not include denormalized floating point values.

imaginary and complex types

D currently supports imaginary and complex versions of all floating point types.
float a = 2;
ifloat b = 4i;
cfloat c = a + b;
assert(c == 2 + 4i);

Corrective Action

Use the library types in std.complex.

Rationale

These types are too specialized to be a part of the core language.

floating point NCEG operators

D currently supports the NCEG floating point operators (!<>=, <>, <>=, !>, !>=, !<, !<=, !<>) for comparisons involving NaNs.

Corrective Action

Use the normal operators and std.math.isNaN.

Rationale

These operators are too specialized to be a part of the core language.

.sort and .reverse properties for arrays

D arrays can be manipulated using these built-in properties.
int[] x = [2, 3, 1];
assert(x.sort == [1, 2, 3]);

Corrective Action

Use the generic functions in std.algorithm.

Rationale

These operations are better implemented in the standard library.

delete

Memory allocated on the GC heap can be freed with delete.
auto a = new Class();
delete a;

Corrective Action

Use object.destroy() instead.

auto a = new Class();
destroy(a);

Rationale

delete makes assumptions about the type of garbage collector available that limits which implementations can be used, and can be replaced by a library solution.

overriding without override

Virtual functions can currently override a function in a base class without the 'override' attribute.
class A
{
    void fun() {}
}
class B : A
{
    // overrides but is not marked with override
    void fun() {}
}

Corrective Action

Mark overriding functions with 'override'

class A
{
    void fun() {}
}
class B : A
{
    override void fun() {}
}

Rationale

Making the 'override' attribute mandatory makes it explicit, and can catch errors when a base class function is accidentally overridden.

scope for allocating classes on the stack

The scope keyword can be used to allocate class objects on the stack:
class A
{
    int x;
    this(int x) { this.x = x; }
}

void main()
{
    A obj;
    {
        scope A a = new A(1);
        obj = a;
    }
    assert(obj.x == 1);  // fails, 'a' has been destroyed
}

Corrective Action

Use scoped from std.typecons

class A
{
    this(int x) { }
}
void main()
{
    A a = scoped!A(1);
}

Rationale

scope was an unsafe feature. A reference to a scoped class could easily be returned from a function without errors, which would make using such an object undefined behavior due to the object being destroyed after exiting the scope of the function it was allocated in. To discourage it from general-use but still allow usage when needed a library solution was implemented.

Note that scope for other usages (e.g. scoped variables) is unrelated to this feature and will not be deprecated.

Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Promoting D Projects (or Internet Marketing 101) - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Promoting D Projects (or Internet Marketing 101)

So you've written a cool project in D, and it's ready for others to use or to get involved with helping develop it further. Just posting a zip file isn't going to work. All your blood, sweat and effort will just go to waste. You'll need to provide a way for people who want to know about your project to be able to find it.

The steps are:

  1. Create a web page for the project
  2. Let people know about it

Creating a Web Page

A good web page should include the following:

  • The keywords and phrases that someone who would be interested in your project might type into Google to find it.
  • The phrase D programming language somewhere on the page. This helps build the brand on the internet. If you just use D, nobody will find it via search.
  • Screen shots of the program. Even better, for graphics and game demos, make a short video of it with Windows Movie Maker, which can capture movies directly from the screen.
  • List the capabilities of the package and what it's good for.
  • Identify who this package is intended for and why they'd want to use it.
  • Copyright and license information for any source code. If you intend for it to be public domain, make sure to explicitly mark it so.

Promoting the Project

Submit the page or article to the following:

  • digitalmars.D.announce newsgroup
  • Google web crawler
  • Google code search for source code zips
  • dzone developer news
  • beta marker for releases, including betas
  • Digg under the Developer category
  • Slashdot news for nerds
  • gamedev.net anything game related
  • Artima Developer developer articles
  • download.com software downloads
  • Wikipedia if it genuinely adds to an article on the subject
  • comp.programming newsgroup

Send me a cut-and-paste html snippet to place on dlinks.

If your project is a conversion of an existing project to D, email the project leader of that existing project and suggest that he incorporate a link to your project on his page.

For the absolutely most effective results, submit articles to:

  • Dr. Dobb's Journal
  • SDWest
  • OOPSLA
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Template Comparison - D Programming Language

Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Template Comparison

C++ pioneered templates and template metaprogramming, and continues to improve on it with C++0x. The D programming language is the first to comprehensively reengineer templates based on the C++ experience. Since C++0x is not a ratified standard yet, proposed changes to C++ are subject to change.

Template Comparison Table
Feature | D | C++98 | C++0x
Argument list delineation Uses !( ), as in Foo!(int).
Can omit parens when the argument is a single lexical token: Foo!int 		Uses < > as in Foo<int> No change
Class Templates Yes:
class Foo(T)
{
  T x;
}
Yes:
template<class T>
  class Foo
{
  T x;
};
No change
Function Templates Yes:
T foo(T)(T i)
{
  ...
}
Yes:
template<class T>
  T foo(T i)
{
  ...
}
No change
Member Templates | Yes | Yes | No change
Constructor Templates | No | Yes | No change
Parameterize any Declaration Yes, classes, functions, typedefs, variables, enums, etc. can be parameterized, such as this variable:
template Foo(T)
{
  static T* p;
}
No, only classes and functions No change
Template Typedefs: Create an alias that binds to some but not all of the template parameters Yes:
class Foo(T, U) { }
template MyFoo(T)
{
  alias Foo!(T, int) MyFoo;
}
MyFoo!(uint) f;
No Yes:
template<class T, class U> class Foo { };
template<class T> using MyFoo = Foo<T, int>;
MyFoo<unsigned> f;
Sequence Constructors No No Yes:
Foo<double> f = { 1.2, 3, 6.8 };
Concepts | Yes: Constraints | No | Yes: Concepts for C++0x N1849
Recursive Templates Yes:
template factorial(int n)
{
  const factorial =
     n * factorial!(n-1);
}
template factorial(int n : 1)
{
  const factorial = 1;
}
Yes:
template<int n> class factorial
{
  public:
    enum
    {
      result =
         n * factorial<n-1>::result
    };
};
template<> class factorial<1>
{
  public:
    enum { result = 1 };
};
No change
Conditional Compilation based on Template Arguments Yes:
template factorial(int n)
{
  static if (n == 1)
    const factorial = 1;
  else
    const factorial =
       n * factorial!(n-1);
}
No:
template<int n> class factorial
{
  public:
    enum
    {
#if (n == 1) // error
      result = 1;
#else
      result =
         n * factorial<n-1>::result
#endif
    };
};
No change
Template Declarations (with no definition) No Yes:
template<class T>
  class Foo;
No change
Grouping templates with the same parameters together Yes:
template Foo(T, U)
{
  class Bar { ... }
  T foo(T t, U u) { ... }
}
Foo!(int,long).Bar b;
return Foo!(char,int).foo('c',3);
No, each must be separate:
template<class T, class U>
  class Foo_Bar { ... };
template<class T, class U>
  T Foo_foo(T t, U u) { ... };
Foo_Bar<int,long> b;
return Foo_foo<char,int>('c',3);
No change
Compile time execution of functions Yes:
int factorial(int i)
{ if (i == 0)
    return 1;
  else
    return i * factorial(i - 1);
}
static f = factorial(6);
No Named constant expressions with parameters: Generalized Constant Expressions N1972
Parameters | D | C++98 | C++0x
Type Parameters Yes:
class Foo(T)
{
  T x;
}
Foo!(int) f;
Yes:
template<class T>
  class Foo
{
  T x;
};
Foo<int> f;
No change
Integral Parameters Yes:
void foo(int i)()
{
  int v = i;
}
Yes:
template<int i>
    void foo()
{
  int v = i;
}
No change
Pointer Parameters | Yes, a pointer to object or function | Yes, a pointer to object or function | No change
Reference Parameters No, D does not have a general reference type Yes:
template<double& D>
    void foo()
{
  double y = D;
}
No change
Pointer to Member Parameters | No, D does not have pointers to members, it has delegates, which can be used as parameters | Yes | No change
Template Template Parameters Yes:
class Foo(T, alias C)
{
  C!(T) x;
}
Yes:
template<class T,
         template<class U> class C>
    class Foo
{
  C<T> x;
};
No change
Alias Parameters Yes, any symbol can be passed to a template as an alias:
void bar(int);
void bar(double);
void foo(T, alias S)(T t)
{
  S(t);
}
// calls bar(double)
foo!(double, bar)(1);
No No change
Floating Point Parameters Yes:
class Foo(double D)
{
  double x = D;
}
...
Foo!(1.6) F;
No No change
String Parameters Yes:
void foo(char[] format)(int i)
{
  writefln(format, i);
}
...
foo!("i = %s")(3);
No No change
Local Class Parameters | Yes | No | Issue N1945
Local Variable Parameters | Yes | No | No change
Parameter Default Values Yes:
class Foo(T = int)
{
  T x;
}
Yes:
template<class T = int>
  class Foo
{
  T x;
};
No change
Variadic Parameters Yes, Variadic Templates:
void print(A...)(A a)
{
    foreach(t; a)
    writefln(t);
}
No Variadic Templates N2080
Specializations | D | C++98 | C++0x
Explicit Specialization Yes:
class Foo(T : int)
{
  T x;
}
Yes:
template<>
  class Foo<int>
{
  int x;
};
No change
Partial Specialization Yes:
class Foo(T : T*, U)
{
  T x;
}
Yes:
template<class T, class U>
  class Foo<T*, U>
{
  T x;
};
No change
Partial specialization derived from multiple parameters Yes:
class Foo(T : Bar!(T, U), U)
{
  ...
}
Yes:
template<class T, class U>
    class Foo< Bar<T,U> >
{
  ...
};
No change
Can specializations exist without a primary template? | Yes | No | No change
Other | D | C++98 | C++0x
Exported Templates | Yes, it falls out as a natural consequence of modules | Yes, though only in compilers based on EDG's front end | No change
SFINAE (Substitution Failure Is Not An Error) | Yes | Yes | No change
Parse Template Definition Bodies before Instantiation | Yes | Not required by Standard, but some implementations do | No change
Overloading Function Templates with Functions No, but the equivalent can be done with explicitly specialized templates:
void foo(T)(T t) { }
void foo(T:int)(int t) { }
Yes:
template<class T>
  void foo(T i) { }
void foo(int t) { }
No change
Implicit Function Template Instantiation | Yes | Yes | No change
Templates can be evaluated in scope of instantiation rather than definition | Yes, Mixins | No, but can be faked using macros | No change
Can extract arguments of template instance Yes:
class Foo(T)
{
  static if (is(T x : T!A, A...))
  {
    pragma(msg, A);  // (int, float)
  }
}

struct Bar(T1, T2) { }
alias Bar!(int, float) BarInst;
Foo!(BarInst) f;
See is expressions. 		No No change
Parsing Idiosyncracies | D | C++98 | C++0x
Context-Free Grammar Yes:
class Foo(int i)
{
   ...
}
Foo!(3 > 4) f;
No:
template<int i> class Foo
{
   ...
};
Foo<3 > 4> f; // error
No change
Distinguish template arguments from other operators Yes:
class Foo(T)
{
   ...
}
class Bar(int i)
{
   ...
}
Foo!(Bar!(1)) x1;
No:
template<class T> class Foo
{
   ...
};
template<int i> class Bar
{
   ...
};
Foo<Bar<1>> x1; // error
Foo<Bar<1> > x2;
Partially fixed by Right Angle Brackets N1757
Redeclaration of Template Parameter Yes:
class Foo(T)
{
  int T;
  void foo()
  {
    int T;
  }
}
No:
template<class T>
  class Foo
{
  int T; // error
  void foo()
  {
    int T; // error
  }
};
No change
Dependent Base Class Lookup Yes:
class Foo(T)
{
  typedef int A;
}
class Bar(T) : Foo(T)
{
  A x;
}
No:
template<class T>
  class Foo
{
  public:
    typedef int A;
};
template<class T>
  class Bar : Foo<T>
{
  public:
    A x; // error
};
No change
Forward Referencing Yes:
int g(void *);

class Foo(T)
{
  int foo()
  {
    return g(1);
  }
}

int g(int i);
No:
int g(void *);

template<class T>
  class Foo
{
  int foo()
  {
    return g(1); // error
  }
};

int g(int i);
No change
Member templates parseable without hints Yes:
class Foo
{
    Foo bar!(int I)();
}
void abd(T)(T f)
{
  T f1 = f.bar!(3)();
}
No:
class Foo
{
  public:
    template<int> Foo *bar();
};
template<class T> void abc(T *f)
{
  T *f1 = f->bar<3>(); // error
  T *f2 = f->template bar<3>();
}
No change
Dependent type members parseable without hints Yes:
class Foo(T)
{
  T.A* a1;
}
No:
template class Foo
{
  public:
    T::A *a1; // error
    typename T::A *a2;
};
No change
Forums | Comments | Search | Downloads | Home
Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on Sun Jan 27 00:15:07 2013


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.fenv

C's <fenv.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.locale

C's <locale.h>

License:
Public Domain

Standards:
ISO/IEC 9899:1999 7.11

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.math

C's <math.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.process

C's <process.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.stdarg

C's <stdarg.h>

Authors:
Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.stddef

C's <stddef.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.stdio

C's <stdio.h> for the D programming language

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.stdlib

C's <stdlib.h> D Programming Language runtime library

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

int setenv(const char*, const char*, int);
extension to ISO C standard, not available on all platforms

int unsetenv(const char*);
extension to ISO C standard, not available on all platforms

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.string

C's <string.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.time

C's <time.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.c.wcharh

C's <wchar.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.cpuid

Deprecated. It will be removed in January 2013. Please use core.cpuid instead.

Identify the characteristics of the host CPU.

Implemented according to:

- AP-485 Intel(C) Processor Identification and the CPUID Instruction http://www.intel.com/design/xeon/applnots/241618.htm

- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M http://developer.intel.com/design/pentium4/manuals/index_new.htm

- AMD CPUID Specification Publication # 25481 http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf

Example:
import std.cpuid;
import std.stdio;

void main()
{
    writefln(std.cpuid.toString());
}

BUGS:
Only works on x86 CPUs

License:
Boost License 1.0.

Authors:
Tomas Lindquist Olsen <tomas@famolsen.dk>

Source:
std/cpuid.d

deprecated string toString();
Returns everything as a printable string

deprecated alias core.cpuid.vendor vendor;
Returns vendor string

deprecated alias core.cpuid.processor processor;
Returns processor string

deprecated alias core.cpuid.mmx mmx;
Is MMX supported?

deprecated alias core.cpuid.hasFxsr fxsr;
Is FXSR supported?

deprecated alias core.cpuid.sse sse;
Is SSE supported?

deprecated alias core.cpuid.sse2 sse2;
Is SSE2 supported?

deprecated alias core.cpuid.sse3 sse3;
Is SSE3 supported?

deprecated alias core.cpuid.ssse3 ssse3;
Is SSSE3 supported?

deprecated alias core.cpuid.amd3dnow amd3dnow;
Is AMD 3DNOW supported?

deprecated alias core.cpuid.amd3dnowExt amd3dnowExt;
Is AMD 3DNOW Ext supported?

deprecated alias core.cpuid.amdMmx amdMmx;
Is AMD MMX supported?

deprecated alias core.cpuid.isItanium ia64;
Is this an Intel Architecture IA64?

deprecated alias core.cpuid.isX86_64 amd64;
Is this an AMD 64?

deprecated alias core.cpuid.hyperThreading hyperThreading;
Is hyperthreading supported?

deprecated alias core.cpuid.threadsPerCPU threadsPerCPU;
Returns number of threads per CPU

deprecated alias core.cpuid.coresPerCPU coresPerCPU;
Returns number of cores in CPU

deprecated @property bool intel();
Is this an Intel processor?

deprecated @property bool amd();
Is this an AMD processor?

deprecated @property uint stepping();
Returns stepping

deprecated @property uint model();
Returns model

deprecated @property uint family();
Returns family

Copyright Tomas Lindquist Olsen 2007 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.ctype

Deprecated. It will be removed in March 2013. Please use std.ascii instead.

Simple ASCII character classification functions. For Unicode classification, see std.uni.

References:
ASCII Table, Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright and Jonathan M Davis

Source:
std/ctype.d

deprecated pure int isalnum(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isAlphaNum instead.

Returns !=0 if c is a letter in the range (0..9, a..z, A..Z).

deprecated pure int isalpha(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isAlpha instead.

Returns !=0 if c is an ascii upper or lower case letter.

deprecated pure int iscntrl(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ctype.ascii.isControl instead.

Returns !=0 if c is a control character.

deprecated pure int isdigit(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isDigit instead.

Returns !=0 if c is a digit.

deprecated pure int islower(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isLower instead.

Returns !=0 if c is lower case ascii letter.

deprecated pure int ispunct(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isPunctuation instead.

Returns !=0 if c is a punctuation character.

deprecated pure int isspace(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isWhite instead.

Returns !=0 if c is a space, tab, vertical tab, form feed, carriage return, or linefeed.

deprecated pure int isupper(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isUpper instead.

Returns !=0 if c is an upper case ascii character.

deprecated pure int isxdigit(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isHexDigit instead.

Returns !=0 if c is a hex digit (0..9, a..f, A..F).

deprecated pure int isgraph(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isGraphical instead.

Returns !=0 if c is a printing character except for the space character.

deprecated pure int isprint(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isPrintable instead.

Returns !=0 if c is a printing character including the space character.

deprecated pure int isascii(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.isASCII instead.

Returns !=0 if c is in the ascii character set, i.e. in the range 0..0x7F.

deprecated pure dchar tolower(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.toLower instead.

If c is an upper case ascii character, return the lower case equivalent, otherwise return c.

deprecated pure dchar toupper(dchar c);
Deprecated. It will be removed in March 2013. Please use std.ascii.toUpper instead.

If c is a lower case ascii character, return the upper case equivalent, otherwise return c.

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.demangle

Demangle D mangled names.

License:
Boost License 1.0.

Authors:
Walter Bright, Thomas Kuehne, Frits van Bommel

Source:
std/demangle.d

string demangle(string name);
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;
}

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.md5

Scheduled for deprecation. Please use std.digest.md instead.

Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities that are like a checksum or crc, but are more robust.

There are two ways to do this. The first does it all in one function call to sum(). The second is for when the data is buffered.

BUGS:
MD5 digests have been demonstrated to not be unique.

Author:
The routines and algorithms are derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.

References:
Wikipedia on MD5

Source:
std/md5.d

Example:
// This code is derived from the
// RSA Data Security, Inc. MD5 Message-Digest Algorithm.

import std.md5;
import std.stdio;

void main(string[] args)
{
    foreach (arg; args)
        mdFile(arg);
}

/// Digests a file and prints the result.
void mdFile(string filename)
{
    ubyte[16] digest;

    MD5_CTX context;
    context.start();
    foreach (buffer; File(filename).byChunk(64 * 1024))
        context.update(buffer);
    context.finish(digest);
    writefln("MD5 (%s) = %s", filename, digestToString(digest));
}

void sum(ref ubyte[16u] digest, in void[][] data...);
Computes MD5 digest of several arrays of data.

string digestToString(in ubyte[16u] digest);
Converts MD5 digest to a string.

string getDigestString(in void[][] data...);
Gets the digest of all data items passed in.

Example:
string a = "Mary has ", b = "a little lamb";
int[] c = [ 1, 2, 3, 4, 5 ];
string d = getDigestString(a, b, c);

struct MD5_CTX;
Holds context of MD5 computation.

Used when data to be digested is buffered.

void start();
MD5 initialization. Begins an MD5 operation, writing a new context.

void update(const void[] input);
MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context.

void finish(ref ubyte[16u] digest);
MD5 finalization. Ends an MD5 message-digest operation, writing the the message to digest and zeroing the context.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.perf

Platform-independent performance measurement and timing classes.

PerformanceCounter is the main platform-independent timer class provided, covering the most typical use case, measuring elapsed wall-clock time.

The module also provides several Windows-specific timers that can be useful in specialized situations.

Synopsis:
alias PerformanceCounter.interval_t interval_t;
auto timer = new PerformanceCounter;
timer.start();
// do computation
timer.stop();
interval_t elapsedMsec = timer.milliseconds;
writefln("Time elapsed: %s msec", elapsedMsec);
In particular note that stop() must be called before querying the elapsed time.

These classes were ported to D from the STLSoft C++ libraries, which were documented in the article " Win32 Performance Measurement Options", May 2003 issue of Windows Develper Network.

Author:
Matthew Wilson

Source:
std/perf.d

class PerformanceCounter;
A performance counter that uses the most accurate measurement APIs available on the host machine

On Linux, the implementation uses gettimeofday(). For Windows, QueryPerformanceCounter() is used if available, GetTickCount() otherwise.

alias long interval_t;
The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class TickCounter;
A low-cost, low-resolution performance counter

This class provides low-resolution, but low-latency, performance monitoring.

This class is available only on Windows, but is guaranteed to be meaningful on all Windows operating systems.

alias long interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class ThreadTimesCounter;
A performance counter that provides thread-specific performance timings

This class uses the operating system's performance monitoring facilities to provide timing information pertaining to the calling thread only, irrespective of the activities of other threads on the system. This class does not provide meaningful timing information on operating systems that do not provide thread-specific monitoring.

This class is available only on Windows.

alias long interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

this();
Constructor

Creates an instance of the class, and caches the thread token so that measurements will be taken with respect to the thread in which the class was created.

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t kernelPeriodCount();
The elapsed count in the measurement period for kernel mode activity

This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity

const interval_t kernelSeconds();
The number of whole seconds in the measurement period for kernel mode activity

This represents the extent, in whole seconds, of the measurement period for kernel mode activity

const interval_t kernelMilliseconds();
The number of whole milliseconds in the measurement period for kernel mode activity

This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity

const interval_t kernelMicroseconds();
The number of whole microseconds in the measurement period for kernel mode activity

This represents the extent, in whole microseconds, of the measurement period for kernel mode activity

const interval_t userPeriodCount();
The elapsed count in the measurement period for user mode activity

This represents the extent, in machine-specific increments, of the measurement period for user mode activity

const interval_t userSeconds();
The number of whole seconds in the measurement period for user mode activity

This represents the extent, in whole seconds, of the measurement period for user mode activity

const interval_t userMilliseconds();
The number of whole milliseconds in the measurement period for user mode activity

This represents the extent, in whole milliseconds, of the measurement period for user mode activity

const interval_t userMicroseconds();
The number of whole microseconds in the measurement period for user mode activity

This represents the extent, in whole microseconds, of the measurement period for user mode activity

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class ProcessTimesCounter;
A performance counter that provides process-specific performance timings

This class uses the operating system's performance monitoring facilities to provide timing information pertaining to the calling process only, irrespective of the activities of other processes on the system. This class does not provide meaningful timing information on operating systems that do not provide process-specific monitoring.

This class is available only on Windows.

alias long interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t kernelPeriodCount();
The elapsed count in the measurement period for kernel mode activity

This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity

const interval_t kernelSeconds();
The number of whole seconds in the measurement period for kernel mode activity

This represents the extent, in whole seconds, of the measurement period for kernel mode activity

const interval_t kernelMilliseconds();
The number of whole milliseconds in the measurement period for kernel mode activity

This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity

const interval_t kernelMicroseconds();
The number of whole microseconds in the measurement period for kernel mode activity

This represents the extent, in whole microseconds, of the measurement period for kernel mode activity

const interval_t userPeriodCount();
The elapsed count in the measurement period for user mode activity

This represents the extent, in machine-specific increments, of the measurement period for user mode activity

const interval_t userSeconds();
The number of whole seconds in the measurement period for user mode activity

This represents the extent, in whole seconds, of the measurement period for user mode activity

const interval_t userMilliseconds();
The number of whole milliseconds in the measurement period for user mode activity

This represents the extent, in whole milliseconds, of the measurement period for user mode activity

const interval_t userMicroseconds();
The number of whole microseconds in the measurement period for user mode activity

This represents the extent, in whole microseconds, of the measurement period for user mode activity

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.regexp

Deprecated. Please use std.regex instead.

Regular expressions are a powerful method of string pattern matching. The regular expression language used in this library is the same as that commonly used, however, some of the very advanced forms may behave slightly differently. The standard observed is the ECMA standard for regular expressions.

std.regexp is designed to work only with valid UTF strings as input. To validate untrusted input, use std.utf.validate().

In the following guide, pattern[] refers to a regular expression. The attributes[] refers to a string controlling the interpretation of the regular expression. It consists of a sequence of one or more of the following characters:

Attribute Characters
Attribute | Action
g | global; repeat over the whole input string
i | case insensitive
m | treat as multiple lines separated by newlines

The format[] string has the formatting characters:

Formatting Characters
Format | Replaced With
$$ | $
$& | The matched substring.
$` | The portion of string that precedes the matched substring.
$' | The portion of string that follows the matched substring.
$n | The nth capture, where n is a single digit 1-9 and n is not followed by a decimal digit.
$nn | The nnth capture, where nn is a two-digit decimal number 01-99. If nnth capture is undefined or more than the number of parenthesized subexpressions, use the empty string instead.

Any other $ are left as is.

References:
Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/regexp.d

deprecated string email;
Regular expression to extract an email address.

References:
How to Find or Validate an Email Address
RFC 2822 Internet Message Format

deprecated string url;
Regular expression to extract a url

class RegExpException: object.Exception;
One of these gets thrown on compilation errors

deprecated string sub(string s, string pattern, string format, string attributes = null);
Search string for matches with regular expression pattern with attributes. Replace each match with string generated from format.

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string format | Replacement string format.
string attributes | Regular expression attributes.

Returns:
the resulting string

Example:
Replace the letters 'a' with the letters 'ZZ'.
 s = "Strap a rocket engine on a chicken."
 sub(s, "a", "ZZ")        // result: StrZZp a rocket engine on a chicken.
 sub(s, "a", "ZZ", "g")   // result: StrZZp ZZ rocket engine on ZZ chicken.
The replacement format can reference the matches using the $&, $$, $', $`, .. 9 notation:
 sub(s, "[ar]", "[$&]", "g") // result: St[r][a]p [a] [r]ocket engine on [a] chi

deprecated string sub(string s, string pattern, string delegate(RegExp) dg, string attributes = null);
Search string for matches with regular expression pattern with attributes. Pass each match to delegate dg. Replace each match with the return value from dg.

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string delegate(RegExp) dg | Delegate
string attributes | Regular expression attributes.

Returns:
the resulting string.

Example:
Capitalize the letters 'a' and 'r':
 s = "Strap a rocket engine on a chicken.";
 sub(s, "[ar]",
    delegate char[] (RegExp m)
    {
         return toUpper(m[0]);
    },
    "g");    // result: StRAp A Rocket engine on A chicken.

deprecated ptrdiff_t find(string s, RegExp pattern);
Search s[] for first match with pattern.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
index into s[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 find(s, RegExp("b"));    // match, returns 1
 find(s, RegExp("f"));    // no match, returns -1

deprecated ptrdiff_t find(string s, string pattern, string attributes = null);
Returns:
Same as find(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.find(s, p, a), you may want to use find(s, RegExp(p, a)).

deprecated ptrdiff_t rfind(string s, RegExp pattern);
Search s[] for last match with pattern.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
index into s[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 rfind(s, RegExp("b"));    // match, returns 9
 rfind(s, RegExp("f"));    // no match, returns -1

deprecated ptrdiff_t rfind(string s, string pattern, string attributes = null);
Returns:
Same as rfind(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.rfind(s, p, a), you may want to use rfind(s, RegExp(p, a)).

deprecated string[] split(string s, RegExp pattern);
Split s[] into an array of strings, using the regular expression pattern as the separator.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
array of slices into s[]

Example:
 foreach (s; split("abcabcabab", RegExp("C.", "i")))
 {
     writefln("s = '%s'", s);
 }
 // Prints:
 // s = 'ab'
 // s = 'b'
 // s = 'bab'

deprecated string[] split(string s, string pattern, string attributes = null);
Returns:
Same as split(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.split(s, p, a), you may want to use split(s, RegExp(p, a)).

deprecated RegExp search(string s, string pattern, string attributes = null);
Search s[] for first match with pattern[] with attributes[].

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string attributes | Regular expression attributes.

Returns:
corresponding RegExp if found, null if not.

Example:
 import std.stdio;
 import std.regexp;

 void main()
 {
     if (auto m = std.regexp.search("abcdef", "c"))
     {
         writefln("%s[%s]%s", m.pre, m[0], m.post);
     }
 }
 // Prints:
 // ab[c]def

class RegExp;
RegExp is a class to handle regular expressions.

It is the core foundation for adding powerful string pattern matching capabilities to programs like grep, text editors, awk, sed, etc.

this(string pattern, string attributes = null);
Construct a RegExp object. Compile pattern with attributes into an internal form for fast execution.

Parameters:
string pattern | regular expression
string attributes | attributes

Throws:
RegExpException if there are any compilation errors.

Example:
Declare two variables and assign to them a RegExp object:
 auto r = new RegExp("pattern");
 auto s = new RegExp(r"p[1-5]\s*");

static RegExp opCall(string pattern, string attributes = null);
Generate instance of RegExp.

Parameters:
string pattern | regular expression
string attributes | attributes

Throws:
RegExpException if there are any compilation errors.

Example:
Declare two variables and assign to them a RegExp object:
 auto r = RegExp("pattern");
 auto s = RegExp(r"p[1-5]\s*");

RegExp search(string string);
int opApply(scope int delegate(ref RegExp) dg);
Set up for start of foreach loop.

Returns:
search() returns instance of RegExp set up to search string[].

Example:
 import std.stdio;
 import std.regexp;

 void main()
 {
     foreach(m; RegExp("ab").search("abcabcabab"))
     {
         writefln("%s[%s]%s", m.pre, m[0], m.post);
     }
 }
 // Prints:
 // [ab]cabcabab
 // abc[ab]cabab
 // abcabc[ab]ab
 // abcabcab[ab]

string opIndex(size_t n);
Retrieve match n.

n==0 means the matched substring, n>0 means the n'th parenthesized subexpression. if n is larger than the number of parenthesized subexpressions, null is returned.

string match(size_t n);
Same as opIndex(n).

WARNING:
Scheduled for deprecation due to confusion with overloaded match(string). Instead of regex.match(n) you may want to use regex[n].

@property string pre();
Return the slice of the input that precedes the matched substring.

@property string post();
Return the slice of the input that follows the matched substring.

string[] split(string s);
Split s[] into an array of strings, using the regular expression as the separator.

Returns:
array of slices into s[]

ptrdiff_t find(string string);
Search string[] for match with regular expression.

Returns:
index of match if successful, -1 if not found

string[] match(string s);
Search s[] for match.

Returns:
If global attribute, return same value as exec(s). If not global attribute, return array of all matches.

string replace(string s, string format);
Find regular expression matches in s[]. Replace those matches with a new string composed of format[] merged with the result of the matches. If global, replace all matches. Otherwise, replace first match.

Returns:
the new string

string[] exec(string s);
Search string[] for match.

Returns:
array of slices into string[] representing matches

string[] exec();
Pick up where last exec(string) or exec() left off, searching string[] for next match.

Returns:
array of slices into string[] representing matches

bool test(string s);
Search s[] for match.

Returns:
0 for no match, !=0 for match

Example:
import std.stdio;
import std.regexp;
import std.string;

int grep(int delegate(char[]) pred, char[][] list)
{
  int count;
  foreach (s; list)
  {  if (pred(s))
       ++count;
  }
  return count;
}

void main()
{
  auto x = grep(&RegExp("[Ff]oo").test,
                std.string.split("mary had a foo lamb"));
  writefln(x);
}
which prints: 1

int test();
Pick up where last test(string) or test() left off, and search again.

Returns:
0 for no match, !=0 for match

int test(string s, size_t startindex);
Test s[] starting at startindex against regular expression.

Returns:
0 for no match, !=0 for match

string replace(string format);
After a match is found with test(), this function will take the match results and, using the format string, generate and return a new string.

string replaceOld(string format);
Like replace(char[] format), but uses old style formatting:
Format | Description
& replace with the match
\n | replace with the nth parenthesized match, n is 1..9
\c | replace with char c.

Copyright Digital Mars 2000 - 2011. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.stdint

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:

Exact Alias | Description | At Least Alias | Description | Fast Alias | Description
int8_t | exactly 8 bits signed | int_least8_t | at least 8 bits signed | int_fast8_t | fast 8 bits signed
uint8_t | exactly 8 bits unsigned | uint_least8_t | at least 8 bits unsigned | uint_fast8_t | fast 8 bits unsigned
int16_t | exactly 16 bits signed | int_least16_t | at least 16 bits signed | int_fast16_t | fast 16 bits signed
uint16_t | exactly 16 bits unsigned | uint_least16_t | at least 16 bits unsigned | uint_fast16_t | fast 16 bits unsigned
int32_t | exactly 32 bits signed | int_least32_t | at least 32 bits signed | int_fast32_t | fast 32 bits signed
uint32_t | exactly 32 bits unsigned | uint_least32_t | at least 32 bits unsigned | uint_fast32_t | fast 32 bits unsigned
int64_t | exactly 64 bits signed | int_least64_t | at least 64 bits signed | int_fast64_t | fast 64 bits signed
uint64_t | exactly 64 bits unsigned | uint_least64_t | at least 64 bits unsigned | uint_fast64_t | fast 64 bits unsigned

The ptr aliases are integral types guaranteed to be large enough to hold a pointer without losing bits:

Alias | Description
intptr_t | signed integral type large enough to hold a pointer
uintptr_t | unsigned integral type large enough to hold a pointer

The max aliases are the largest integral types:

Alias | Description
intmax_t | the largest signed integral type
uintmax_t | the largest unsigned integral type

License:
Boost License 1.0.

Authors:
Walter Bright

Source:
std/stdint.d

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.windows.registry

This library provides Win32 Registry facilities.

License:

Author:
Matthew Wilson, Kenji Hara

Histry:
Created 15th March 2003, Updated 25th April 2004,

Source:
std/windows/registry.d

class Win32Exception: object.Exception;

class RegistryException: std.windows.registry.Win32Exception;
Exception class thrown by the std.windows.registry classes.

this(string message, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null);
Creates an instance of the exception.

Parameters:
string message The message associated with the exception.

this(string message, int error, string fn = __FILE__, size_t ln = __LINE__, Throwable next = null);
Creates an instance of the exception, with the given.

Parameters:
string message | The message associated with the exception.
int error | The Win32 error number associated with the exception.

enum REGSAM;
Enumeration of the recognised registry access modes.

KEY_QUERY_VALUE
Permission to query subkey data

KEY_SET_VALUE
Permission to set subkey data

KEY_CREATE_SUB_KEY
Permission to create subkeys

KEY_ENUMERATE_SUB_KEYS
Permission to enumerate subkeys

KEY_NOTIFY
Permission for change notification

KEY_CREATE_LINK
Permission to create a symbolic link

KEY_WOW64_32KEY
Enables a 64- or 32-bit application to open a 32-bit key

KEY_WOW64_64KEY
Enables a 64- or 32-bit application to open a 64-bit key

KEY_WOW64_RES

KEY_WRITE
Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access rights

KEY_EXECUTE
Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights

KEY_ALL_ACCESS
Permission for read access

enum REG_VALUE_TYPE;
Enumeration of the recognised registry value types.

REG_UNKNOWN

REG_NONE
The null value type. (In practise this is treated as a zero-length binary array by the Win32 registry)

REG_SZ
A zero-terminated string

REG_EXPAND_SZ
A zero-terminated string containing expandable environment variable references

REG_BINARY
A binary blob

REG_DWORD
A 32-bit unsigned integer

REG_DWORD_LITTLE_ENDIAN
A 32-bit unsigned integer, stored in little-endian byte order

REG_DWORD_BIG_ENDIAN
A 32-bit unsigned integer, stored in big-endian byte order

REG_LINK
A registry link

REG_MULTI_SZ
A set of zero-terminated strings

REG_RESOURCE_LIST
A hardware resource list

REG_FULL_RESOURCE_DESCRIPTOR
A hardware resource descriptor

REG_RESOURCE_REQUIREMENTS_LIST
A hardware resource requirements list

REG_QWORD
A 64-bit unsigned integer

REG_QWORD_LITTLE_ENDIAN
A 64-bit unsigned integer, stored in little-endian byte order

class Key;
This class represents a registry key.

const pure nothrow @property @safe string name();
The name of the key

const @property size_t keyCount();
The number of sub keys.

pure @property @safe KeySequence keys();
An enumerable sequence of all the sub-keys of this key.

pure @property @safe KeyNameSequence keyNames();
An enumerable sequence of the names of all the sub-keys of this key.

const @property size_t valueCount();
The number of values.

pure @property @safe ValueSequence values();
An enumerable sequence of all the values of this key.

pure @property @safe ValueNameSequence valueNames();
An enumerable sequence of the names of all the values of this key.

Key createKey(string name, REGSAM access = (REGSAM).KEY_ALL_ACCESS);
Returns the named sub-key of this key.

Parameters:
string name The name of the subkey to create. May not be null.

Returns:
The created key.

Throws:
RegistryException is thrown if the key cannot be created.

Key getKey(string name, REGSAM access = (REGSAM).KEY_READ);
Returns the named sub-key of this key.

Parameters:
string name | The name of the subkey to aquire. If name is the empty string, then the called key is duplicated.
REGSAM access | The desired access; one of the REGSAM enumeration.

Returns:
The aquired key.

Throws:
This function never returns null. If a key corresponding to the requested name is not found, RegistryException is thrown.

void deleteKey(string name, REGSAM access = cast(REGSAM)0);
Deletes the named key.

Parameters:
string name The name of the key to delete. May not be null.

Value getValue(string name);
Returns the named value. If name is the empty string, then the default value is returned.

Returns:
This function never returns null. If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, uint value);
Sets the named value with the given 32-bit unsigned integer value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
uint value | The 32-bit unsigned value to set.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, uint value, Endian endian);
Sets the named value with the given 32-bit unsigned integer value, according to the desired byte-ordering.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
uint value | The 32-bit unsigned value to set.
Endian endian | Can be Endian.BigEndian or Endian.LittleEndian.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, ulong value);
Sets the named value with the given 64-bit unsigned integer value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
ulong value | The 64-bit unsigned value to set.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, string value);
Sets the named value with the given string value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
string value | The string value to set.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, string value, bool asEXPAND_SZ);
Sets the named value with the given string value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
string value | The string value to set.
bool asEXPAND_SZ | If 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, RegistryException is thrown.

void setValue(string name, string[] value);
Sets the named value with the given multiple-strings value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
string[] value | The multiple-strings value to set.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void setValue(string name, byte[] value);
Sets the named value with the given binary value.

Parameters:
string name | The name of the value to set. If it is the empty string, sets the default value.
byte[] value | The binary value to set.

Throws:
If a value corresponding to the requested name is not found, RegistryException is thrown.

void deleteValue(string name);
Deletes the named value.

Parameters:
string name The name of the value to delete. May not be null.

Throws:
If a value of the requested name is not found, RegistryException is thrown.

void flush();
Flushes any changes to the key to disk.

class Value;
This class represents a value of a registry key.

const pure nothrow @property @safe string name();
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.

const pure nothrow @property @safe REG_VALUE_TYPE type();
The type of value.

const @property string value_SZ();
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; value_EXPAND_SZ should be called

Returns:
The contents of the value.

Throws:
RegistryException if the type of the value is not REG_SZ, REG_EXPAND_SZ, REG_DWORD, or REG_QWORD.

const @property string value_EXPAND_SZ();
Obtains the current value as a string, within which any environment variables have undergone expansion. This function works with the same value-types as value_SZ.

Returns:
The contents of the value.

const @property string[] value_MULTI_SZ();
Obtains the current value as an array of strings.

Returns:
The contents of the value.

Throws:
RegistryException if the type of the value is not REG_MULTI_SZ.

const @property uint value_DWORD();
Obtains the current value as a 32-bit unsigned integer, ordered correctly according to the current architecture.

Returns:
The contents of the value.

Throws:
RegistryException is thrown for all types other than REG_DWORD, REG_DWORD_LITTLE_ENDIAN and REG_DWORD_BIG_ENDIAN.

const @property ulong value_QWORD();
Obtains the value as a 64-bit unsigned integer, ordered correctly according to the current architecture.

Returns:
The contents of the value.

Throws:
RegistryException if the type of the value is not REG_QWORD.

const @property byte[] value_BINARY();
Obtains the value as a binary blob.

Returns:
The contents of the value.

Throws:
RegistryException if the type of the value is not REG_BINARY.

class Registry;
Represents the local system registry.

static @property Key classesRoot();
Returns the root key for the HKEY_CLASSES_ROOT hive

static @property Key currentUser();
Returns the root key for the HKEY_CURRENT_USER hive

static @property Key localMachine();
Returns the root key for the HKEY_LOCAL_MACHINE hive

static @property Key users();
Returns the root key for the HKEY_USERS hive

static @property Key performanceData();
Returns the root key for the HKEY_PERFORMANCE_DATA hive

static @property Key currentConfig();
Returns the root key for the HKEY_CURRENT_CONFIG hive

static @property Key dynData();
Returns the root key for the HKEY_DYN_DATA hive

class KeyNameSequence;
An enumerable sequence representing the names of the sub-keys of a registry Key.

Example:
Key key = ...
foreach (string subkeyName; key.keyNames)
{
    // using subkeyName
}

const @property size_t count();
The number of keys.

string getKeyName(size_t index);
The name of the key at the given index.

Parameters:
size_t 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 opIndex(size_t index);
The name of the key at the given index.

Parameters:
size_t 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.

int opApply(scope int delegate(ref string name) dg);

class KeySequence;
An enumerable sequence representing the sub-keys of a registry Key.

Example:
Key key = ...
foreach (Key subkey; key.keys)
{
    // using subkey
}

const @property size_t count();
The number of keys.

Key getKey(size_t index);
The key at the given index.

Parameters:
size_t index The 0-based index of the key to retrieve.

Returns:
The key corresponding to the given index.

Throws:
RegistryException if no corresponding key is retrieved.

Key opIndex(size_t index);
The key at the given index.

Parameters:
size_t index The 0-based index of the key to retrieve.

Returns:
The key corresponding to the given index.

Throws:
RegistryException if no corresponding key is retrieved.

int opApply(scope int delegate(ref Key key) dg);

class ValueNameSequence;
An enumerable sequence representing the names of the values of a registry Key.

Example:
Key key = ...
foreach (string valueName; key.valueNames)
{
    // using valueName
}

const @property size_t count();
The number of values.

string getValueName(size_t index);
The name of the value at the given index.

Parameters:
size_t index The 0-based index of the value to retrieve.

Returns:
The name of the value corresponding to the given index.

Throws:
RegistryException if no corresponding value is retrieved.

string opIndex(size_t index);
The name of the value at the given index.

Parameters:
size_t index The 0-based index of the value to retrieve.

Returns:
The name of the value corresponding to the given index.

Throws:
RegistryException if no corresponding value is retrieved.

int opApply(scope int delegate(ref string name) dg);

class ValueSequence;
An enumerable sequence representing the values of a registry Key.

Example:
Key key = ...
foreach (Value value; key.values)
{
    // using value
}

const @property size_t count();
The number of values

Value getValue(size_t index);
The value at the given index.

Parameters:
size_t index The 0-based index of the value to retrieve

Returns:
The value corresponding to the given index.

Throws:
RegistryException if no corresponding value is retrieved

Value opIndex(size_t index);
The value at the given index.

Parameters:
size_t index The 0-based index of the value to retrieve.

Returns:
The value corresponding to the given index.

Throws:
RegistryException if no corresponding value is retrieved.

int opApply(scope int delegate(ref Value value) dg);

Copyright 2003-2004 by Matthew Wilson and Synesis Software Written by Matthew Wilson | Page generated by Ddoc.