Home
License
Documentation
FAQ
Examples
Download
Contact

Tips

Write once, build many times...

When developing cross platform applications with Reason it is important that you constantly compile your source code on all the target platforms.

Windows and Linux both have their idiosyncrasies, and it is much easier to fix a small number of syntax errors than it is to port an entire application at once.

This software is licensed under the CC-GNU GPL.

CC-GNU GPL

Documentation & Examples

Reason contains many classes that you would see in other frameworks like Java or .Net as well as many that you wouldn't.

It also includes a comprehensive object hierarchy with its own form of run time type inference. Notably absent are inbuilt C++ rtti and exception handling. This is deliberate and by design as it makes the framework faster and more portable.

Fundamentals
Objects
Strings
Dates & Times
Files & Folders
Collections
Iterators
Streams
Components
Parser
Xml & Xpath
Sql
Regexes
Logging
Javascript
Css
Html
Advanced
Threading
Networking
Security
Graphics
Messaging
Machine Learning
Text Analysis

Classes are separated into major namespaces like System, Structure, Network, and Language. In addition each major namespace has several sub namespaces sometimes by classification like Storage and sometimes by the name of a standard like Xml.

Every effort has been made to make these namespaces as obvious and intuitive as possible.

Fundamentals

Objects

namespace Reason::System

Object is an abstract base class which defines several methods such as Print(), Compare(), Equals() and Hash(). It is used as the base class for many of Reason's built in types, such as String, Path, and Url.

All Object's are inherently compatible with the collection classes within Reason and are often also used as the polymorphic base types in many of the components.

Strings

namespace Reason::System

Unlike many frameworks, Reason features many classes for string handling. This is in recognition of the fact that there are many ways in which strings can be used.

Each type of string is a specialisation or a means of explicit optimisation. For example Reason has a class for substrings and another one for strings used to create other strings, or superstrings.

But you don't have to worry about them if you don't want too, String has everything you need inlcuding a variety of methods for comparing and modifying strings.

String string;
string = "hello world";

/* Substring is used for partial strings. It acts as a reference to memory used by another string. */
Substring substring;
substring = string.Substring(string.IndexOf(" "));
substring.Trim();

/* Superstring is used for temporary strings, it reduces memory when copying and is the default class used for the + operator. */
Superstring superstring;
superstring = Superstring("hello") +" "+ Superstring("world");

/* Path is used for strings which have components. They allow strings to be split and their components to be modified whilst updating the string as a whole. Path's are the basis for many classes in Reason such as Url's, File's, and Folder's. */
Path path = string;
path.Split(" ");
path[0].Uppercase();
path[1].Replace("WORLD");

Strings also have methods for checking and converting between types. For example you might want to extract a floating point or integer number from a string.

String string("3.14159");

// Conver the string to an integer 3
int i = string.Integer();

// Convert the string to a flaoting point 3.14159
double d = string.Float();

// Convert a string to a hexadecimal number 255
long l = String("FF").Hex();

if (string.IsAlphanumeric() || String("CC").IsHex())
{
    // ...
}

All strings are also Sequence's, so they can be easily used in any circumstance where the Sequence class is supported. Sequence simply represents a sequence of bytes.

String string;
// All strings classes are sequences, but sequence is abstract
string.Allocate(255);
string.Append("hello");

/* Sequence defines the two member variables which all string classes share, these are Data and Size */

// String::Length() checks for null, strlen() just crashes
memcpy(string.Data+string.Size-1," world",String::Length("world");
string.Terminate();

/* Notice that if you want to you can treat a string as a C string and do all kinds of nasty pointer things to them */

bool is = string.Is("hello world");

Strings of all types can be printed using the Print() method which is inherited from Object. If a Substring calls Print() then the substring is copied to a threadsafe circular printing buffer before returning a pointer. A String just returns the pointer to its Data member.

Dates & Times

namespace Reason::System

Rather than just basic time and date support Reason contains a comprehensive set of classes for dealing with presentation and converting between times and time formats.

All times used in Reason are local time only. Reason deliberately does not make any attempt to automatically adjust for daylight savings time or apply timezone information.

Other frameworks and even the standard C library make assumptions about times which programmers use which are often wrong. You don't want times from a Sql database which mean something in the local timezone of the database to be converted to the local timezone of your computer without knowing about it.

Likewise, if the time or date is changed whilst your application is running, you dont want your times within the application to be affected by this change. Reason ensures that no timezone information can corrupt its representations.

The date and time classes include Calendar, Time, Epoch, and Interval. Most classes can be freely converted form one form to another.

Time represents an integer time as used by most operating systems. It is the number of seconds since a particular moment in time, or epoch. For example, unix represents time as the number of seconds since January 1st 1970.

// The time now
Time now;

// Todays calendar date
Calendar today(now);

// Yesterdays calendar date
Calendar yesterday(today - Time::SecondsPerDay);

// Days between 1970 and yesterday
int days = yesterday.Days("1/1/1970");

Calendar can be used to parse almost any time format possible and will resolve inconsistencies between U.S. and other date formats. European/Australiasian date formats are the assumed standard.

// Parse the time and date
String string = "Thursday April 21, @04:32PM";

Calendar calendar(string);

if (calendar.Day == 21 && calendar.Hour == 16 && calendar.Minute == 32)
{
    // ...
}

// These formats will also work
calendar.Construct("21 Apr 2005 20:56");
calendar.Construct("April 21, 2005: 5:06 PM EDT");
calendar.Construct("20 Apr 2005");
calendar.Construct("15:25:14 04/21/2005");
calendar.Construct("15:25:14");

// Or if you wanted to parse a time from a piece of text
String text = ", and 21:00 ambitious documentary";
Calendar calendar;
int index=0;
while (!calendar.Construct(text.Substring(index)))
{
    index = text.IndexOf(index+1," ");
    if (index == -1) break;
}

The Epoch class can be used to model a moment in time with a number of ticks at a given scale. This is used for converting between time formats used both within and between operating systems. For example Windows has a different concept for file time than it does for system time.

/* These two epochs represent standard unix time and windows system time versus windows file time */
Epoch posix("01 Jan 1970 00:00:00");
Epoch windows("01 Jan 1601, 00:00:00",0,10000000);

double elapsed = posix - windows;
long long ticks = elapsed*windows.Scale;

if (ticks == 116444736000000000LL)
{
    // ...
}

The Interval class is used to represent a period of time. Since time is not scalar, when you subtract two times what you end up with is an interval. It supports a full range of integer additions and subtractions with overloaded operators like + and -.

// Compare two dates
Calendar after("2/2/2000");
Calendar before("1/1/1000");

bool less = before < after;

Also available are Date, Day, Week, Month, and Year classes which can be used for presentation and for extracting specific information from a Time or a Calendar.

Files & Folders

namespace Reason::System::Storage

All filesystem operations in Reason are represented by the Filesystem class which encapsulates the notion of a filesystem path and contains basic methods like Status() and Exists() as well as members like Properties which allow you to query filesystem information.

Both the File class and the Folder class inherit from Filsystem. File provides methods for reading from and writing too al kinds of files as well as operations like Rename(), Seek(), and Truncate().

// Open and read from a file
File file("readme.txt");
String string;

/* There is no need to open a file before use, calling the read method will always attempt to open the file as readable. If the file does not exist it will be created automatically */
file.Read(string);

/* But if we want to write to the file now we must close it or reopen it as writable */
file.Close();
file.Write("hello world");

/* Of course, we could always open the file for both reading and writing */
file.Open(File::OPTIONS_OPEN_TEXT_MUTABLE);

/* Seek to the end of the file, the first parameter specifies the position and the second parameter specifies the origin. Origins are start < 0, current == 0, finish > 0 */
file.Seek(0,1);

file.Construct("example.txt");
if (file.Exists() && Time(file.Properties.Modified) < Time() - Time::SecondsPerHour)
{
    file.Delete();
}
else
{
    file.Create();
}

File's also inherit from two interfaces, Reader, and Writer which make them compatible with all stream operations.

Folder allows manipulatin and iteration over files and folders, as well as creation and deletion of files and folders.

// Open a folder and list its contents
Folder folder("/home");
folder.List();

// Now we can iterate through the files or folders
for (folder.Files.MoveFirst(); folder.Files.Has(); folder.Files.MoveNext())
{
/* The name is a pointer to a Path component, File and Folder both inherit from Path */
    String name = *folder.Files().Name
    name.Uppercase();
    folder.Files().Name->Replace(name);
    folder.Files().Construct();
    folder.Files().Create();
}

// And we can sort them before iteration
int order = Orderable::ORDER_DESCENDING;
folder.Folders.Sort(order);

// Creating sub folders or files is easy
folder.CreateFile("new.txt");
folder.CreateFolder("admin");

Collections

namespace Reason::Structure

No feature defines a framework more than collections, and Reason is no exception.

Reason contains all of the usual collection classes as generic C++ templates and also a number of classes which have been specialised for use with Object's.

The primary difference between the collections offered by Reason and those by other C++ frameworks is that the template classes in Reason are simple to use and easy to understand. In fact they are on par, if not better than those available in .Net or Java.

/* Create an array of integers, this uses the overloaded , operator to assign a list of values */
Array<int> array = 1,2,3,4,5;

// Create a list of strings and sort them
List<String> list;
list.Append("a");
list.Append("d");
list.Append("c");
list.Append("b");
list.Append(String((char)'d' + array[0]));

list.Sort(Orderable::ORDER_DESCENDING);

// Create a set of pointers, and then destroy them
Set<Object*> set;
set.Insert(new String("five"));
set.Insert(new Number(5));
Number * number = new Number(5);
if (!set.Insert(number)
{
    delete number;
}
// No memory leaks here...
set.Destroy();

C++ template code can be incredibly complicated, most implementations of STL are a testament to this. The Reason template classes are not only readable, they are reliable and 100% cross platform, just like the rest of the framework.

They are also extremely flexible and fast, one of the side effects of simplicity.

The collection classes contain a number of useful concepts which you will notice extend throughout the Reason namespaces. One such concept is the idea that collections manage the lifecycle of the objects which they contain.

If a collection contains pointers, you have the option of reclaiming all the memory using a simple call to Destroy(). Likewise most collections have both a Delete() and a Remove() method.

/* As well as ordered sets and maps, there are unordered sets and maps, as well as multimaps and multisets */
Hashtable<int> table;
table.Insert(1);
table.Insert(2);
table.Insert(3);
table.Select(1);

Map<Object *,String> map(Comparable::COMPARE_GENERAL);
map.Insert(new Number(10),"z");
map.Insert(new Number(5),"a");
Number number(5);
map.Insert(&number,"b");

/* because the insertion above will fail, we can safely destroy all of the keys. All maps let you destroy either the keys or the values or both */
map.DestroyKeys();

/* The multimap will allow duplicate keys, that is of course what makes it a multi-map. When the values are not pointers calling destroy on them should do nothing */
Multimap<Object *,String> multi(Comparable::COMPARE_INSTANCE);
multi.Insert(new Number(10),"z");
multi.Insert(new Number(5),"a");
multi.Insert(new Number(5),"b");
multi.Insert(new Number(5),"c");
multi.DestroyKeys();
multi.DestroyValues();

Another concept is that things which can be compared can be compared in a number of different ways. Classes which inherit from Object like String, or Folder can be compared using generic, precise, or instance comparisons.

This is because sometimes when you have a collection of String pointers you want to compare them in a case insenstive way, whilst others you may want to compare as case sensitive. Or perhaps you actually just want to compare the pointers themselves.

Reason does not force the user to construct custom compare functions or functors unless they really want to. It comes in built with the flexibility to allow a wide range of polymorphic comparisons.

The collections also use naming conventions familiar to anyone who has ever used a database. Most classes support methods like Insert(), Update(), Select(), and Delete().

You can safely inherit from Reason's collection classes. They have been designed with this in mind, unlike STL which explicitly forbids inheritance.

Iterators

namespace Reason::Structure

Of course, no modern software framework is complete without iterators. Reason uses a combination of metaphores in its iterator design, it is part STL like pointer and part Java or .Net like class.

I like to think its the best of both. Iterator's in Reason are used as classes but iterate over the Iterable interface using classes called Iterands and Iterations.

/* Whenever we insert something into a map we get an iterand which tells us if the insertion was succesful. The iterand wraps whatever internal storage type is used in the collection */
Hashmap<int,String> hashmap;
hashmap.Insert(1,"a");

Iterand< Mapped<int,String> > iterand;
iterand = hashmap.Insert(2,"b");
if (iterand)
{
    hashmap.Remove(1);
}

/* You don't have to use this verbose description of the iterator types. Every collection defines typedefs of their iterator types, but i prefer to see what im iterating. Note that a map is really just a set of Mapped items, its a very thin wrapper. Mapped is very similar to Pair in concept and behaviour */
Iterator< Mapped<int,String> > iterator;
iterator = hashmap.Iterate();
for(iterator.MoveFirst();iterator.Has();iterator.MoveNext())
{
    int i = iterator().Key();
    String string = iterator().Value();
}

Iterand is a smart pointer like class which provides a generic interface to all types which can be iterated. It is also the return type for most collection methods. It provides a common way to iterate and return complex types, pointers, and primitive types whilst still being able to check for success or failure.

Iteration's are classes used by the abstract collection types to hold state about the Iterator which is currently being used. They provide a mechanism for Iterator's to be invalidated during iteration and also a way for multiple Iterators to be iterating a collection at the same time.

One of the major advantages of the appraoch to iteration that Reason uses, over say STL, is that Iterator's are types in their own right. So you can define a function which takes an Iterator<int> and it does not matter wether that iterator came from a List or an Array. Likewise all collections which use the Mapped class use the same iterator interface, so Map, Set, Hashset, and Hashmap all have the same iterator.

Bjarn Stroustrup once defined C++ templates as being parametric polymorphism. But that doesn't mean they can't also be object oriented.

Reasons templates are object oriented, and so are its iterators.

Streams

namespace Reason::System
namespace Reason::System::Storage
namespace Reason::System::Security
namespace Reason::System::Encoding
namespace Reason::Language::Text
namespace Reason::Network

Streams are an important part of any modern software framework as they provide a mechanism for processing data.

Unlike other C++ frameworks, and even the standard C++ library. Streams in Reason have nothing to do with the << and >> operators.

/* Stream itself is an abstract class so we must create an instance of some other class which implements it */

String write = "This String will be written to the StringStream.";
String read;

StringStream stringStream;
stringStream.Write(write);

bool is = stringStream.Is(write);
bool size = stringStream.Size == write.Size;
bool position = stringStream.Position == write.Size;

int size = String::Length("StringStream.");
stringStream.Seek(stringStream.Position-size);

Information which is transmitted across a network can be processed as it arrives using a Stream, allowing for better use of local resources and asynchronous operation. In addition Stream's can be used for processing data which is too large to fit in memory.

Stream's can also be used as buffers for increasing network performance or reading efficiently from a file. The StreamBuffer class can turn any Stream into a buffered stream.

All Stream's in Reason can be either absolute, or relative streams. This means that they either support Seek() and therefore random acces, like a file. Or they are sequential and do not support Seek() like a network socket.

The Stream class inherits from the Reader and Writer interfaces. So by definition all streams in Reason are potentially mutable. To find out wether a Stream is both readable and writable you should call the IsReadable() and IsWritable() methods.

There are inbuilt streams for strings, files, text, sockets, compression, checksums, encoding, serialisation, and encryption.

The classes are StringStream, FileStream, TextStream, TextFileStream, SocketStream, GzipStream, RawStream, DeflateStream, ChecksumStream, CodecStream, PrimitiveStream, and HashStream.

Several of the stream classes also contain adapters for mapping between existing classes and the Stream class. For example, if you have a Stream which you want to behave as a File, you can pass it through the FileStream::FileAdapter class.

If you have a File which you want to use as a Stream you can use the FileStream::StreamAdapter class, though most of the time that wont be ncessessary since File inherits from the same Reader/Writer interfaces as Stream. Likewise if you have a String which you want to use as a Stream you can use the String::StreamAdapter.

Components

Parser

namespace Reason::System

Parsing is fundamental to everything that Reason does.

Having a well thought out and consistent approach to parsing is one of the things which makes Reason so simple to understand and maintainable.

/* Parse tab or comma delimited data from a file and store it in a table structure */

FileStream stream("data.csv");
List< Array<String> > table;

/* Parser requires an instance of Scanner. There are two default implementations of the Scanner interface, StringScanner and StreamScanner. But you can just use the wrappers */
StreamParser parser(stream);

int row=0;

/* Parser has an internal substring called token which you mark at the start of a sequence of bytes and trap at the end. When parsing String's you can also mark and trap any number of user supplied substrings by passing them as an argument.

Basically the mark just sets the Data, and the trap sets the Size. A substring of size 0 will evaluate false with the IsEmpty() method.*/

parser.Mark();
while(!parser.Eof())
{
    if (parser.IsAny("\t,"))
    {
        parser.Trap();
        table[row].Append(parser.Token);
        parser.Skip();
        parser.Mark();
    }
    else
    if (parser.IsNewLine())
    {
        parser.Trap();
        table[row].Append(parser.Token);
        parser.SkipNewLine();
        parser.Mark();

        ++row;
        table.Append(Array<String>());
    }
    else
    {
        parser.Next();
    }

}

parser.Trap();
if (!parser.Token.IsEmpty())
{
    table[row].Append(parser.Token);
}

All of the protocols and standards implemented in Reason use the Parser class. There are numerous highly customisable hand crafted recursive descent parsers for things form Url's to the Javascript language.

The Parser is guaranteed to only look ahead in a Stream as far as has been necessary to meet the requirements of the interface. Likewise it will only buffer as much of the Stream as is necessary to maintain its internal token.

For instance the Is(5,"hello") method will look ahead exactly 5+String::Length("hello"), so you can safely use the Parser for processing things like HTTP responses during keep-alive connections.

The parser also supports the notion of state, its base class, called Scanner, provides everything that is needed to load and store state on String's and absolute Stream's. Relative Stream's by necesity can only store a limited amount of state, namely whatever is in the buffer.

Xml & Xpath

namespace Reason::Language::Xml

Reason contains complete implementations of XML 1.0, and XPath 1.0/2.0 including a validating parser with full DTD support.

/* The xml document and similar classes all support three methods of creation, Load(), Download(), and Create(). */
XmlDocument document;
document.Load("shopping.xml");

XmlPathNavigator navigator(&document);
navigator.Select("//cheese");

for (navigator.MoveFirst();navigator.Has();navigator.MoveNext())
{
    XmlObject * object = navigator();
}

The XPath implementation is second to none and heavily optimised for speed and extendability. Whilst the XML parser is as forgiving or as sctrict as you require. It can easily parse and repair invalid HTML using information from the schema.

Sql

namespace Reason::Language::Sql

Reason includes a generic database api with support for both MySQL and SqLite databases.

All database operations are completely thread safe. The classes include support for prepared statements, recordsets and records, as well as transactions.

Statments can be executed using printf style format specifiers using the Execute() method on the SqlDatabase class.

There are overloads which provide support for SqlRecordset's and SqlRecord's to be returned from an Execute() call.

/* You can share a sql driver between multiple databases, it doesnt really matter unless you want to customise behaviour of the driver or track connections */
MySql mysql;

SqlRecordset recordset;
SqlDatabase database(&mysql);
database.Open("test", "user", "pass", "localhost" ,3306);
database.Execute(recordset,"select * from test");

int count = recordset.Count;
if (recordset.Fields[0].Is("name"))
{
    String string = recordset(0,0);
}

datatbase.Execute("drop table garbage");

All SQL which is executed through the variable arguments version of the database Execute() method is automatically checked for SQL injection attacks. All quotes and special characters are escaped.

This means that a large number of potential vulnerabilities are avoided. Of course you should still use prepared statements for maximum safety.

If you wish to pass in a string which has been externally sanitised, or if you just want to play hacker, you can always use the version of the database Execute() method which takes a Sequence.

/* SqLite is super cool. You can create local filesystem databases, temporary databases, and in memory databases. Notice that both SqLite and MySql use the same set of database classes and interfaces */
SqLite sqlite;
SqlRecord record;
// Lets create an in memory temporary database
SqlDatabase memorydb(&sqlite);
memorydb.Open(SqLite::Memory);

// Insert some records
memorydb.Execute("create table hashes(url varchar(200),hash varchar(32))");
memorydb.Execute("insert into hashes values('http://cnn.com/index.html','9CD0D01540E3E01')");
memorydb.Execute("insert into hashes values('http://cnn.com/privacy.html','BA365969B17906')");

// Now lets iterate it one record at a time
if (memorydb.Execute(record,"select * from hashes"))
{
    do
    {
        String hash = record[2];
    }
    while(record.Step());
}

Reason also includes helper classes like SqlTime and SqlFormatter which are designed to aid in construction and processing of SQL queries.

Regexes

namespace Reason::Language::Regular

Logging

namespace Reason::System::Logging

Advanced

Threading

namespace Reason::System::Threads

Networking

namespace Reason::Network

Networking is embedded in many of the components in Reason. Classes like Url and XmlDocument all allow you to download things from any standard internet url.

Its very simple, just call the Download() method, and in the case of Url, supply a String where you wish the content to be placed.

// Download something and save it to disk
String string;

Url url("http://pics.obra.se/Yarly.jpg");
url.Download(string);

File("/tmp/" + url.Filename()).Write(string);


// Download an xml document
XmlDocument document;
document.Download("http://www.digg.com/rss/index.xml");

/* You can nest calls to navigator like this, of course its usually more efficient to write a direct path expression like //item/title */
XmlPathNavigator navigator;
navigator.Select(&document,"//item");
for(navigator.MoveFirst();navigator.Has();navigator.MoveNext())
{
    String title;
    XmlPathNavigator item(navigator());
    if (item.Select("title"))
        title = item()->Token;
}

But if you want to do something a little more serious, you can use the low level TCP/IP classes like Address and Socket to build just about any kind of networking functionality you need.

Socket supports both synchronous and asycnhronous operation through the same class, so you can make use of blocking or non blocking behaviour on all platforms.

// Resolve the local hostname
char * host = SocketLibrary::ResolveHostname();

// Resolve the local address
unsigned long addr = SocketLibrary::ResolveAddress();

/* Create a socket on port 80 and bind to that address and you have an instant web server */
Address local(addr,80);
Socket server;
server.Bind(local);
server.Listen();

Address remote;
Socket client;
while(server.Accept(client,remote))
{
    String buffer;
    buffer.Allocate(1024);

    if ((buffer.Size=client.Read(buffer.Data,buffer.Allocated)) > 0
    && buffer.StartsWith("GET "))
    {
        buffer.Format("HTTP/1.x 200 Ok\r\nConnection: close
        \r\n\r\n<html><body>Welcome %s</body></html>
        \r\n\r\n"
,remote.Ip());
        client.Send(buffer.Data,buffer.Size);
    }

    client.Close();
}

If you want to use non blocking sockets you can either change the Socket mode using the Mode() method or supply the mode in the constructor.

The following example illustrates how this can be used to create an efficient non blocking connection handler.

The Connection class provides a convinient way of managing Address's and Socket's.

// A simple non blocking io socket server.
List<Connection*> connections;

Socket listener(Socket::SOCKET_MODE_ASYNCHRONOUS);
/* You might want to bind to a specific addres, or all available addresses */

listener.Bind(Address(Address::ADDRESS_TYPE_ANY,8080));
// listener.Bind(Address(SocketLibrary::ResolveAddress(),8080));

listener.Listen();

Connection * connection = new Connection(Socket::SOCKET_MODE_ASYNCHRONOUS);

Time future;
future += 10; // 10 seconds from now

do
{
    if(listener.Accept(connection->Socket,connection->Address))
    {
        connections.Append(connection);
        connection = new Connection(Socket::SOCKET_MODE_ASYNCHRONOUS);
    }

    for(int i=0;i<connections.Length();++i)
    {
        String string;
        string.Allocate(1024);
        int read = connections[i]->Socket.Read(string.Data,string.Allocated);
        if (read == 0 && !connections[i]->Socket.IsReadable())
            connections.DeleteAt(i);
        else
           string.Size = read;
    }

    // Wait 100 milliseconds between accepting connections     Thread::Sleep(100);
}
while(Time() < future);

delete connection;
connections.Destroy();

There are also classes for working with common protocols like HTTP. You can use HttpClient or HttpServer along with HttpRequest and HttpResponse to construct your own web server or client. Reason is ideal for developing and deploying simple XML based web services.

There is also a HttpManager class along with an HttpService class for building simple servlet style HTTP request processing components.

Security

namespace Reason::System::Security

Copyright 2007 - Reason Limited