Skip to content

Instantly share code, notes, and snippets.

@Hackerpilot
Created March 30, 2015 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hackerpilot/9708cfa7ce0e259f1600 to your computer and use it in GitHub Desktop.
Save Hackerpilot/9708cfa7ce0e259f1600 to your computer and use it in GitHub Desktop.
Issue 14323 test case
// Compiling with -versio=WTF_DMD causes good codegen
// Compiling without this version set causes bad codegen
struct State
{
this(uint breaks, const Token[] tokens, immutable short[] depths,
const Config* config, int currentLineLength, int indentLevel)
{
import std.math : abs;
import core.bitop : popcnt, bsf;
import std.algorithm : min, map, sum;
// TODO: Figure out what is going on here.
version (WTF_DMD)
{
enum int remainingCharsMultiplier = 40;
enum int newlinePenalty = 800;
}
else
{
immutable int remainingCharsMultiplier = config.columnHardLimit - config.columnSoftLimit;
immutable int newlinePenalty = remainingCharsMultiplier * 20;
assert(remainingCharsMultiplier == 40);
assert(newlinePenalty == 800);
}
int cost = 0;
for (size_t i = 0; i != uint.sizeof * 8; ++i)
{
if (((1 << i) & breaks) == 0)
continue;
immutable b = tokens[i].type;
immutable p = abs(depths[i]);
immutable bc = breakCost(b) * (p == 0 ? 1 : p * 2);
cost += bc;
}
int ll = currentLineLength;
bool solved = true;
if (breaks == 0)
{
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
cost = l;
if (l > config.columnSoftLimit)
{
immutable int longPenalty = (l - config.columnSoftLimit) * remainingCharsMultiplier;
cost += longPenalty;
solved = longPenalty < newlinePenalty;
}
else
solved = true;
}
else
{
size_t i = 0;
foreach (_; 0 .. uint.sizeof * 8)
{
immutable size_t k = breaks >>> i;
immutable bool b = k == 0;
immutable size_t j = min(i + bsf(k) + 1, tokens.length);
ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
if (ll > config.columnHardLimit)
{
solved = false;
break;
}
else if (ll > config.columnSoftLimit)
cost += (ll - config.columnSoftLimit) * remainingCharsMultiplier;
i = j;
ll = indentLevel * config.indentSize;
if (b)
break;
}
}
cost += popcnt(breaks) * newlinePenalty;
this.breaks = breaks;
this._cost = cost;
this._solved = solved;
}
uint breaks;
private:
int _cost;
bool _solved;
}
struct Token
{
ubyte type;
string text;
}
int breakCost(ubyte u) pure nothrow @safe @nogc
{
switch (u)
{
case 50: return 400;
case 1: return 0;
case 65: return 1000;
default: assert(false);
}
}
int tokenLength(ref const Token t) pure @safe @nogc
{
switch (t.type)
{
case 50: return 1;
case 65: return cast(int) t.text.length;
case 1: return 2;
default: assert (false);
}
}
struct Config
{
int columnHardLimit = 120;
int columnSoftLimit = 80;
int indentSize = 4;
}
void main()
{
import std.range:zip;
import std.stdio:writeln;
uint breaks = 1;
string[] tokenText = [null, "one", null, "two", null, "three", null, "four", null, "five", null, "six", null, "seven", null, "eight", null, "nine", null, "ten", null, "eleven", null, "twelve", null, "thirteen", null, "fourteen"];
immutable ubyte[] tokenTypes = [50, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65];
Token[] tokens = new Token[](tokenText.length);
foreach (i; 0 .. tokenText.length)
{
tokens[i].text = tokenText[i];
tokens[i].type = tokenTypes[i];
}
immutable short[] depths = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];
Config c;
int currentLineLength = 24;
int indentLevel = 1;
auto s = State(breaks, tokens, depths, &c, currentLineLength, indentLevel);
writeln(s._cost); // 3080 or 2400
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment