Better performance

This commit is contained in:
Hackerpilot 2013-02-03 01:32:16 +00:00
parent ccb4023ec0
commit 4adaae9e06
3 changed files with 305 additions and 257 deletions

View File

@ -17,13 +17,15 @@ void writeSpan(string cssClass, string value)
// http://ethanschoonover.com/solarized // http://ethanschoonover.com/solarized
void highlight(R)(R tokens) void highlight(R)(TokenRange!R tokens, string fileName)
{ {
stdout.writeln(q"EOS stdout.writeln(q"[
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>]");
stdout.writeln("<title>", fileName, "</title>");
stdout.writeln(q"[</head>
<body> <body>
<style type="text/css"> <style type="text/css">
html { background-color: #fdf6e3; color: #002b36; } html { background-color: #fdf6e3; color: #002b36; }
@ -35,8 +37,7 @@ html { background-color: #fdf6e3; color: #002b36; }
.type { color: #268bd2; font-weight: bold; } .type { color: #268bd2; font-weight: bold; }
.cons { color: #859900; font-weight: bold; } .cons { color: #859900; font-weight: bold; }
</style> </style>
<pre> <pre>]");
EOS");
foreach (Token t; tokens) foreach (Token t; tokens)
{ {

7
main.d
View File

@ -140,6 +140,7 @@ int main(string[] args)
if (tokenCount) if (tokenCount)
{ {
import core.memory;
/+if (args.length == 1) /+if (args.length == 1)
{ {
writeln((cast (ubyte[]) stdin.byLine(KeepTerminator.yes).join()).byToken().walkLength()); writeln((cast (ubyte[]) stdin.byLine(KeepTerminator.yes).join()).byToken().walkLength());
@ -151,11 +152,12 @@ int main(string[] args)
{ {
config.fileName = arg; config.fileName = arg;
uint count; uint count;
//GC.disable();
foreach(t; byToken(cast(ubyte[]) File(arg).byLine(KeepTerminator.yes).join(), config)) foreach(t; byToken(cast(ubyte[]) File(arg).byLine(KeepTerminator.yes).join(), config))
{ {
writeln(t);
++count; ++count;
} }
//GC.enable();
writefln("%s: %d", arg, count); writefln("%s: %d", arg, count);
} }
/+}+/ /+}+/
@ -193,7 +195,8 @@ int main(string[] args)
config.iterStyle = IterationStyle.everything; config.iterStyle = IterationStyle.everything;
config.tokenStyle = TokenStyle.source; config.tokenStyle = TokenStyle.source;
File f = args.length == 1 ? stdin : File(args[1]); File f = args.length == 1 ? stdin : File(args[1]);
highlighter.highlight((cast(ubyte[]) f.byLine(KeepTerminator.yes).join()).byToken(config)); highlighter.highlight((cast(ubyte[]) f.byLine(KeepTerminator.yes).join()).byToken(config),
args.length == 1 ? "stdin" : args[1]);
return 0; return 0;
} }

View File

@ -119,8 +119,7 @@ import std.traits;
import std.uni; import std.uni;
import std.utf; import std.utf;
import std.regex; import std.regex;
import std.container;
import std.stdio;
public: public:
@ -268,7 +267,7 @@ struct LexerConfig
/** /**
* Replacement for the ___VERSION__ token. Defaults to 1. * Replacement for the ___VERSION__ token. Defaults to 1.
*/ */
uint versionNumber = 1; uint versionNumber = 100;
/** /**
* Replacement for the ___VENDOR__ token. Defaults to $(D_STRING "std.d.lexer") * Replacement for the ___VENDOR__ token. Defaults to $(D_STRING "std.d.lexer")
@ -415,6 +414,7 @@ private:
{ {
this.range = range; this.range = range;
buffer = new ubyte[config.bufferSize]; buffer = new ubyte[config.bufferSize];
cache.initialize();
} }
/* /*
@ -631,7 +631,7 @@ private:
current.type = lookupTokenType(cast(char[]) buffer[0 .. bufferIndex]); current.type = lookupTokenType(cast(char[]) buffer[0 .. bufferIndex]);
current.value = getTokenValue(current.type); current.value = getTokenValue(current.type);
if (current.value is null) if (current.value is null)
current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; setTokenValue();
if (!(config.iterStyle & IterationStyle.ignoreEOF) && current.type == TokenType.eof) if (!(config.iterStyle & IterationStyle.ignoreEOF) && current.type == TokenType.eof)
{ {
@ -693,7 +693,7 @@ private:
keepChar(); keepChar();
} }
if (config.iterStyle & IterationStyle.includeWhitespace) if (config.iterStyle & IterationStyle.includeWhitespace)
current.value = (cast(char[]) buffer[0..bufferIndex]).idup; setTokenValue();
} }
void lexComment() void lexComment()
@ -759,7 +759,7 @@ private:
assert(false); assert(false);
} }
if (config.iterStyle & IterationStyle.includeComments) if (config.iterStyle & IterationStyle.includeComments)
current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; setTokenValue();
} }
void lexHexString() void lexHexString()
@ -770,20 +770,13 @@ private:
body body
{ {
current.type = TokenType.stringLiteral; current.type = TokenType.stringLiteral;
size_t i; keepChar();
if (config.tokenStyle & TokenStyle.includeQuotes) keepChar();
while (true)
{ {
buffer[i++] = 'x'; if (range.isEoF())
buffer[i++] = '"';
}
range.popFront();
range.popFront();
index += 2;
while (!range.isEoF())
{
if (i >= buffer.length)
{ {
errorMessage("Hex string constant exceeded buffer size"); errorMessage("Unterminated hex string literal");
return; return;
} }
else if (isHexDigit(range.front)) else if (isHexDigit(range.front))
@ -796,44 +789,28 @@ private:
} }
else if (range.front == '"') else if (range.front == '"')
{ {
if (config.tokenStyle & TokenStyle.includeQuotes) keepChar();
buffer[i++] = '"';
range.popFront();
++index;
break; break;
} }
else else
{ {
errorMessage(format("Invalid character '%s' in hex string literal", errorMessage(format("Invalid character '%s' in hex string literal",
cast(char) range.front)); cast(char) range.front));
return;
} }
} }
if (!range.isEoF()) lexStringSuffix();
{
switch (range.front)
{
case 'w':
current.type = TokenType.wstringLiteral;
goto case 'c';
case 'd':
current.type = TokenType.dstringLiteral;
goto case 'c';
case 'c':
if (config.tokenStyle & TokenStyle.includeQuotes)
buffer[i++] = range.front;
range.popFront();
++index;
break;
default:
break;
}
}
if (config.tokenStyle & TokenStyle.notEscaped) if (config.tokenStyle & TokenStyle.notEscaped)
current.value = (cast(char[]) buffer[0 .. i]).idup; {
if (config.tokenStyle & TokenStyle.includeQuotes)
setTokenValue();
else
setTokenValue(bufferIndex - 1, 2);
}
else else
{ {
auto a = appender!(ubyte[])(); auto a = appender!(ubyte[])();
foreach (b; std.range.chunks(buffer[0 .. i], 2)) foreach (b; std.range.chunks(buffer[2 .. bufferIndex - 1], 2))
{ {
string s = to!string(cast(char[]) b); string s = to!string(cast(char[]) b);
a.put(cast(ubyte[]) to!string(cast(dchar) parse!uint(s, 16))); a.put(cast(ubyte[]) to!string(cast(dchar) parse!uint(s, 16)));
@ -999,7 +976,7 @@ private:
{ {
bool foundDot = false; bool foundDot = false;
current.type = TokenType.intLiteral; current.type = TokenType.intLiteral;
scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; scope(exit) setTokenValue();
decimalLoop: while (!range.isEoF()) decimalLoop: while (!range.isEoF())
{ {
switch (range.front) switch (range.front)
@ -1049,7 +1026,7 @@ private:
void lexBinary() void lexBinary()
{ {
current.type = TokenType.intLiteral; current.type = TokenType.intLiteral;
scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; scope(exit) setTokenValue();
binaryLoop: while (!range.isEoF()) binaryLoop: while (!range.isEoF())
{ {
switch (range.front) switch (range.front)
@ -1073,7 +1050,7 @@ private:
void lexHex() void lexHex()
{ {
current.type = TokenType.intLiteral; current.type = TokenType.intLiteral;
scope(exit) current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; scope(exit) setTokenValue();
bool foundDot; bool foundDot;
hexLoop: while (!range.isEoF()) hexLoop: while (!range.isEoF())
{ {
@ -1155,13 +1132,13 @@ private:
scope (exit) scope (exit)
{ {
if (config.tokenStyle & TokenStyle.includeQuotes) if (config.tokenStyle & TokenStyle.includeQuotes)
current.value = (cast(char[]) buffer[0..bufferIndex]).idup; setTokenValue();
else else
{ {
if (buffer[0] == 'r') if (buffer[0] == 'r')
current.value = (cast(char[]) buffer[2..bufferIndex - 1]).idup; setTokenValue(bufferIndex - 1, 2);
else else
current.value = (cast(char[]) buffer[1..bufferIndex - 1]).idup; setTokenValue(bufferIndex - 1, 1);
} }
} }
@ -1250,9 +1227,9 @@ private:
scope (exit) scope (exit)
{ {
if (config.tokenStyle & TokenStyle.includeQuotes) if (config.tokenStyle & TokenStyle.includeQuotes)
current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; setTokenValue();
else else
current.value = (cast(char[]) buffer[3 .. bufferIndex - 2]).idup; setTokenValue(bufferIndex - 2, 3);
} }
while (true) while (true)
{ {
@ -1323,7 +1300,7 @@ private:
scope(exit) scope(exit)
{ {
if (config.tokenStyle & TokenStyle.includeQuotes) if (config.tokenStyle & TokenStyle.includeQuotes)
current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; setTokenValue();
else else
{ {
size_t b = 2 + ident.length; size_t b = 2 + ident.length;
@ -1332,8 +1309,7 @@ private:
size_t e = bufferIndex; size_t e = bufferIndex;
if (buffer[e - 1] == 'c' || buffer[e - 1] == 'd' || buffer[e - 1] == 'w') if (buffer[e - 1] == 'c' || buffer[e - 1] == 'd' || buffer[e - 1] == 'w')
--e; --e;
stderr.writeln("b = ", b, " e = ", e); setTokenValue(e, b);
current.value = (cast(char[]) buffer[b .. e]).idup;
} }
} }
@ -1376,9 +1352,9 @@ private:
scope (exit) scope (exit)
{ {
if (config.tokenStyle & TokenStyle.includeQuotes) if (config.tokenStyle & TokenStyle.includeQuotes)
current.value = (cast(char[]) buffer[0 .. bufferIndex]).idup; setTokenValue();
else else
current.value = (cast(char[]) buffer[2 .. bufferIndex - 1]).idup; setTokenValue(bufferIndex - 1, 2);
} }
keepChar(); keepChar();
@ -1514,6 +1490,13 @@ private:
} }
} }
void setTokenValue(size_t endIndex = 0, size_t startIndex = 0)
{
if (endIndex == 0)
endIndex = bufferIndex;
current.value = cache.get(buffer[startIndex .. endIndex]);
}
Token current; Token current;
uint lineNumber; uint lineNumber;
uint index; uint index;
@ -1523,6 +1506,7 @@ private:
ubyte[] buffer; ubyte[] buffer;
size_t bufferIndex; size_t bufferIndex;
LexerConfig config; LexerConfig config;
StringCache cache;
} }
/** /**
@ -1822,207 +1806,207 @@ private:
* To avoid memory allocations Token.value is set to a slice of this string * To avoid memory allocations Token.value is set to a slice of this string
* for operators and keywords. * for operators and keywords.
*/ */
immutable string opKwdValues = //immutable string opKwdValues =
"#/=*=+=++-=--^^=~=<<=%==>>>=||=&&=,;:!<=!<>=!=!>=?...()[]{}@$" // "#/=*=+=++-=--^^=~=<<=%==>>>=||=&&=,;:!<=!<>=!=!>=?...()[]{}@$"
~ "boolcdoublecentcfloatcrealdchardstringfunctionidoubleifloatirealubyte" // ~ "boolcdoublecentcfloatcrealdchardstringfunctionidoubleifloatirealubyte"
~ "ucentuintulongushortvoidwcharwstringaligndeprecatedexternpragmaexport" // ~ "ucentuintulongushortvoidwcharwstringaligndeprecatedexternpragmaexport"
~ "packageprivateprotectedpublicabstractautoconstfinal__gsharedimmutable" // ~ "packageprivateprotectedpublicabstractautoconstfinal__gsharedimmutable"
~ "inoutscopesharedstaticsynchronizedaliasasmassertbodybreakcasecastcatch" // ~ "inoutscopesharedstaticsynchronizedaliasasmassertbodybreakcasecastcatch"
~ "classcontinuedebugdefaultdelegatedeleteelseenumfalsefinally" // ~ "classcontinuedebugdefaultdelegatedeleteelseenumfalsefinally"
~ "foreach_reversegotoimportinterfaceinvariantlazymacromixinmodule" // ~ "foreach_reversegotoimportinterfaceinvariantlazymacromixinmodule"
~ "newnothrownulloverridepurerefreturnstructsuperswitchtemplatethistruetry" // ~ "newnothrownulloverridepurerefreturnstructsuperswitchtemplatethistruetry"
~ "typedeftypeidtypeofunionunittestversionvolatilewhilewith__traits" // ~ "typedeftypeidtypeofunionunittestversionvolatilewhilewith__traits"
~ "__vector__parameters__DATE__EOF__TIME__TIMESTAMP__VENDOR__VERSION__" // ~ "__vector__parameters__DATE__EOF__TIME__TIMESTAMP__VENDOR__VERSION__"
~ "FILE__LINE__"; // ~ "FILE__LINE__";
/* /*
* Slices of the above string to save memory. This array is automatically * Slices of the above string to save memory. This array is automatically
* generated. * generated.
*/ */
immutable(string[]) tokenValues = [ immutable(string[TokenType.max + 1]) tokenValues = [
opKwdValues[2 .. 3], // = "=",
opKwdValues[59 .. 60], // @ "@",
opKwdValues[31 .. 32], // & "&",
opKwdValues[32 .. 34], // &= "&=",
opKwdValues[28 .. 29], // | "|",
opKwdValues[29 .. 31], // |= "|=",
opKwdValues[16 .. 18], // ~= "~=",
opKwdValues[36 .. 37], // : ":",
opKwdValues[34 .. 35], // , ",",
opKwdValues[11 .. 13], // -- "--",
opKwdValues[1 .. 2], // / "/",
opKwdValues[1 .. 3], // /= "/=",
opKwdValues[60 .. 61], // $ "$",
opKwdValues[50 .. 51], // . ".",
opKwdValues[22 .. 24], // == "==",
opKwdValues[23 .. 25], // => "=>",
opKwdValues[24 .. 25], // > ">",
opKwdValues[26 .. 28], // >= ">=",
opKwdValues[0 .. 1], // # "#",
opKwdValues[7 .. 9], // ++ "++",
opKwdValues[57 .. 58], // { "{",
opKwdValues[55 .. 56], // [ "[",
opKwdValues[18 .. 19], // < "<",
opKwdValues[19 .. 21], // <= "<=",
opKwdValues[41 .. 44], // <>= "<>=",
opKwdValues[41 .. 43], // <> "<>",
opKwdValues[31 .. 33], // && "&&",
opKwdValues[28 .. 30], // || "||",
opKwdValues[53 .. 54], // ( "(",
opKwdValues[9 .. 10], // - "-",
opKwdValues[9 .. 11], // -= "-=",
opKwdValues[21 .. 22], // % "%",
opKwdValues[21 .. 23], // %= "%=",
opKwdValues[3 .. 5], // *= "*=",
opKwdValues[37 .. 38], // ! "!",
opKwdValues[44 .. 46], // != "!=",
opKwdValues[46 .. 48], // !> "!>",
opKwdValues[46 .. 49], // !>= "!>=",
opKwdValues[37 .. 39], // !< "!<",
opKwdValues[37 .. 40], // !<= "!<=",
opKwdValues[40 .. 43], // !<> "!<>",
opKwdValues[5 .. 6], // + "+",
opKwdValues[5 .. 7], // += "+=",
opKwdValues[13 .. 15], // ^^ "^^",
opKwdValues[13 .. 16], // ^^= "^^=",
opKwdValues[58 .. 59], // } "}",
opKwdValues[56 .. 57], // ] "]",
opKwdValues[54 .. 55], // ) ")",
opKwdValues[35 .. 36], // ; ";",
opKwdValues[18 .. 20], // << "<<",
opKwdValues[18 .. 21], // <<= "<<=",
opKwdValues[24 .. 26], // >> ">>",
opKwdValues[25 .. 28], // >>= ">>=",
opKwdValues[50 .. 52], // .. "..",
opKwdValues[3 .. 4], // * "*",
opKwdValues[49 .. 50], // ? "?",
opKwdValues[16 .. 17], // ~ "~",
opKwdValues[40 .. 44], // !<>= "!<>=",
opKwdValues[24 .. 27], // >>> ">>>",
opKwdValues[24 .. 28], // >>>= ">>>=",
opKwdValues[50 .. 53], // ... "...",
opKwdValues[13 .. 14], // ^ "^",
opKwdValues[14 .. 16], // ^= "^=",
opKwdValues[61 .. 65], // bool "bool",
opKwdValues[126 .. 130], // byte "byte",
opKwdValues[65 .. 72], // cdouble "cdouble",
opKwdValues[72 .. 76], // cent "cent",
opKwdValues[76 .. 82], // cfloat "cfloat",
opKwdValues[88 .. 92], // char "char",
opKwdValues[82 .. 87], // creal "creal",
opKwdValues[87 .. 92], // dchar "dchar",
opKwdValues[66 .. 72], // double "double",
opKwdValues[92 .. 99], // dstring "dstring",
opKwdValues[77 .. 82], // float "float",
opKwdValues[99 .. 107], // function "function",
opKwdValues[107 .. 114], // idouble "idouble",
opKwdValues[114 .. 120], // ifloat "ifloat",
opKwdValues[136 .. 139], // int "int",
opKwdValues[120 .. 125], // ireal "ireal",
opKwdValues[140 .. 144], // long "long",
opKwdValues[83 .. 87], // real "real",
opKwdValues[145 .. 150], // short "short",
opKwdValues[93 .. 99], // string "string",
opKwdValues[125 .. 130], // ubyte "ubyte",
opKwdValues[130 .. 135], // ucent "ucent",
opKwdValues[135 .. 139], // uint "uint",
opKwdValues[139 .. 144], // ulong "ulong",
opKwdValues[144 .. 150], // ushort "ushort",
opKwdValues[150 .. 154], // void "void",
opKwdValues[154 .. 159], // wchar "wchar",
opKwdValues[159 .. 166], // wstring "wstring",
opKwdValues[166 .. 171], // align "align",
opKwdValues[171 .. 181], // deprecated "deprecated",
opKwdValues[181 .. 187], // extern "extern",
opKwdValues[187 .. 193], // pragma "pragma",
opKwdValues[193 .. 199], // export "export",
opKwdValues[199 .. 206], // package "package",
opKwdValues[206 .. 213], // private "private",
opKwdValues[213 .. 222], // protected "protected",
opKwdValues[222 .. 228], // public "public",
opKwdValues[228 .. 236], // abstract "abstract",
opKwdValues[236 .. 240], // auto "auto",
opKwdValues[240 .. 245], // const "const",
opKwdValues[245 .. 250], // final "final",
opKwdValues[250 .. 259], // __gshared "__gshared",
opKwdValues[259 .. 268], // immutable "immutable",
opKwdValues[268 .. 273], // inout "inout",
opKwdValues[273 .. 278], // scope "scope",
opKwdValues[253 .. 259], // shared "shared",
opKwdValues[284 .. 290], // static "static",
opKwdValues[290 .. 302], // synchronized "synchronized",
opKwdValues[302 .. 307], // alias "alias",
opKwdValues[307 .. 310], // asm "asm",
opKwdValues[310 .. 316], // assert "assert",
opKwdValues[316 .. 320], // body "body",
opKwdValues[320 .. 325], // break "break",
opKwdValues[325 .. 329], // case "case",
opKwdValues[329 .. 333], // cast "cast",
opKwdValues[333 .. 338], // catch "catch",
opKwdValues[338 .. 343], // class "class",
opKwdValues[343 .. 351], // continue "continue",
opKwdValues[351 .. 356], // debug "debug",
opKwdValues[356 .. 363], // default "default",
opKwdValues[363 .. 371], // delegate "delegate",
opKwdValues[371 .. 377], // delete "delete",
opKwdValues[66 .. 68], // do "do",
opKwdValues[377 .. 381], // else "else",
opKwdValues[381 .. 385], // enum "enum",
opKwdValues[385 .. 390], // false "false",
opKwdValues[390 .. 397], // finally "finally",
opKwdValues[397 .. 404], // foreach "foreach",
opKwdValues[397 .. 412], // foreach_reverse "foreach_reverse",
opKwdValues[397 .. 400], // for "for",
opKwdValues[412 .. 416], // goto "goto",
opKwdValues[114 .. 116], // if "if",
opKwdValues[416 .. 422], // import "import",
opKwdValues[96 .. 98], // in "in",
opKwdValues[422 .. 431], // interface "interface",
opKwdValues[431 .. 440], // invariant "invariant",
opKwdValues[522 .. 524], // is "is",
opKwdValues[440 .. 444], // lazy "lazy",
opKwdValues[444 .. 449], // macro "macro",
opKwdValues[449 .. 454], // mixin "mixin",
opKwdValues[454 .. 460], // module "module",
opKwdValues[460 .. 463], // new "new",
opKwdValues[463 .. 470], // nothrow "nothrow",
opKwdValues[470 .. 474], // null "null",
opKwdValues[270 .. 273], // out "out",
opKwdValues[474 .. 482], // override "override",
opKwdValues[482 .. 486], // pure "pure",
opKwdValues[486 .. 489], // ref "ref",
opKwdValues[489 .. 495], // return "return",
opKwdValues[495 .. 501], // struct "struct",
opKwdValues[501 .. 506], // super "super",
opKwdValues[506 .. 512], // switch "switch",
opKwdValues[512 .. 520], // template "template",
opKwdValues[520 .. 524], // this "this",
opKwdValues[465 .. 470], // throw "throw",
opKwdValues[524 .. 528], // true "true",
opKwdValues[528 .. 531], // try "try",
opKwdValues[531 .. 538], // typedef "typedef",
opKwdValues[538 .. 544], // typeid "typeid",
opKwdValues[544 .. 550], // typeof "typeof",
opKwdValues[550 .. 555], // union "union",
opKwdValues[555 .. 563], // unittest "unittest",
opKwdValues[563 .. 570], // version "version",
opKwdValues[570 .. 578], // volatile "volatile",
opKwdValues[578 .. 583], // while "while",
opKwdValues[583 .. 587], // with "with",
opKwdValues[615 .. 623], // __DATE__ "__DATE__",
opKwdValues[621 .. 628], // __EOF__ "__EOF__",
opKwdValues[626 .. 634], // __TIME__ "__TIME__",
opKwdValues[632 .. 645], // __TIMESTAMP__ "__TIMESTAMP__",
opKwdValues[643 .. 653], // __VENDOR__ "__VENDOR__",
opKwdValues[651 .. 662], // __VERSION__ "__VERSION__",
opKwdValues[660 .. 668], // __FILE__ "__FILE__",
opKwdValues[666 .. 674], // __LINE__ "__LINE__",
null, null,
null, null,
null, null,
opKwdValues[587 .. 595], // __traits "__traits",
opKwdValues[603 .. 615], // __parameters "__parameters",
opKwdValues[595 .. 603], // __vector "__vector",
null, null,
null, null,
null, null,
@ -2477,4 +2461,64 @@ string generateCaseTrie(string[] args ...)
return printCaseStatements(t, ""); return printCaseStatements(t, "");
} }
struct StringCache
{
void initialize()
{
pages.length = 1;
}
string get(ubyte[] bytes)
{
import std.stdio;
string* val = (cast(string) bytes) in index;
if (val !is null)
{
return *val;
}
else
{
auto s = insert(bytes);
index[s] = s;
return s;
}
}
private:
immutable pageSize = 1024 * 1024;
string insert(ubyte[] bytes)
{
if (bytes.length >= pageSize)
assert(false);
size_t last = pages.length - 1;
Page* p = &(pages[last]);
size_t free = p.data.length - p.lastUsed;
if (free >= bytes.length)
{
p.data[p.lastUsed .. (p.lastUsed + bytes.length)] = bytes;
p.lastUsed += bytes.length;
return cast(immutable(char)[]) p.data[p.lastUsed - bytes.length .. p.lastUsed];
}
else
{
pages.length++;
pages[pages.length - 1].data[0 .. bytes.length] = bytes;
pages[pages.length - 1].lastUsed = bytes.length;
return cast(immutable(char)[]) pages[pages.length - 1].data[0 .. bytes.length];
}
}
struct Page
{
ubyte[pageSize] data;
size_t lastUsed;
}
Page[] pages;
string[string] index;
}
//void main(string[] args) {} //void main(string[] args) {}