More line wrapping tuning

This commit is contained in:
Hackerpilot 2015-03-23 00:33:59 -07:00
parent 3e4a131069
commit 48bc7ba0c2
1 changed files with 157 additions and 147 deletions

View File

@ -9,23 +9,33 @@ import std.d.lexer;
import dfmt.tokens; import dfmt.tokens;
import dfmt.config; import dfmt.config;
version = WTF_DMD;
struct State struct State
{ {
this(uint breaks, const Token[] tokens, immutable short[] depths, int depth, this(uint breaks, const Token[] tokens, immutable short[] depths,
const Config* config, int currentLineLength, int indentLevel) pure @safe const Config* config, int currentLineLength, int indentLevel) pure @safe
{ {
import std.math : abs; import std.math : abs;
import core.bitop : popcnt, bsf; import core.bitop : popcnt, bsf;
import std.algorithm:min; import std.algorithm : min;
immutable remainingCharsMultiplier = 40;
immutable newlinePenalty = 800;
this.breaks = breaks;
this._depth = depth;
import std.algorithm : map, sum; import std.algorithm : map, sum;
this._cost = 0; // 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) for (size_t i = 0; i != uint.sizeof * 8; ++i)
{ {
if (((1 << i) & breaks) == 0) if (((1 << i) & breaks) == 0)
@ -33,27 +43,27 @@ struct State
immutable b = tokens[i].type; immutable b = tokens[i].type;
immutable p = abs(depths[i]); immutable p = abs(depths[i]);
immutable bc = breakCost(b) * (p == 0 ? 1 : p * 2); immutable bc = breakCost(b) * (p == 0 ? 1 : p * 2);
this._cost += bc; cost += bc;
} }
int ll = currentLineLength; int ll = currentLineLength;
this._solved = true; bool solved = true;
if (breaks == 0) if (breaks == 0)
{ {
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum(); immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
_cost = l; cost = l;
if (l > config.columnSoftLimit) if (l > config.columnSoftLimit)
{ {
immutable longPenalty = (l - config.columnSoftLimit) * remainingCharsMultiplier; immutable int longPenalty = (l - config.columnSoftLimit) * remainingCharsMultiplier;
_cost += longPenalty; cost += longPenalty;
this._solved = longPenalty < newlinePenalty; solved = longPenalty < newlinePenalty;
} }
else else
this._solved = true; solved = true;
} }
else else
{ {
size_t i = 0; size_t i = 0;
foreach (_; 0 .. 32) foreach (_; 0 .. uint.sizeof * 8)
{ {
immutable size_t k = breaks >>> i; immutable size_t k = breaks >>> i;
immutable bool b = k == 0; immutable bool b = k == 0;
@ -61,18 +71,22 @@ struct State
ll += tokens[i .. j].map!(a => tokenLength(a)).sum(); ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
if (ll > config.columnHardLimit) if (ll > config.columnHardLimit)
{ {
this._solved = false; solved = false;
break; break;
} }
else if (ll > config.columnSoftLimit) else if (ll > config.columnSoftLimit)
_cost += (ll - config.columnSoftLimit) * remainingCharsMultiplier; cost += (ll - config.columnSoftLimit) * remainingCharsMultiplier;
i = j; i = j;
ll = indentLevel * config.indentSize; ll = indentLevel * config.indentSize;
if (b) if (b)
break; break;
} }
} }
this._cost += popcnt(breaks) * newlinePenalty; cost += popcnt(breaks) * newlinePenalty;
this.breaks = breaks;
this._cost = cost;
this._solved = solved;
} }
int cost() const pure nothrow @safe @property int cost() const pure nothrow @safe @property
@ -80,11 +94,6 @@ struct State
return _cost; return _cost;
} }
int depth() const pure nothrow @safe @property
{
return _depth;
}
int solved() const pure nothrow @safe @property int solved() const pure nothrow @safe @property
{ {
return _solved; return _solved;
@ -92,9 +101,11 @@ struct State
int opCmp(ref const State other) const pure nothrow @safe int opCmp(ref const State other) const pure nothrow @safe
{ {
import core.bitop : bsf , popcnt; import core.bitop : bsf, popcnt;
if (cost < other.cost || (cost == other.cost && ((popcnt(breaks) if (cost < other.cost || (cost == other.cost && ((popcnt(breaks)
&& popcnt(other.breaks) && bsf(breaks) > bsf(other.breaks)) || (_solved && !other.solved)))) && popcnt(other.breaks) && bsf(breaks) > bsf(other.breaks))
|| (_solved && !other.solved))))
{ {
return -1; return -1;
} }
@ -106,24 +117,24 @@ struct State
return other.breaks == breaks; return other.breaks == breaks;
} }
size_t toHash() const nothrow @safe size_t toHash() const pure nothrow @safe
{ {
return typeid(breaks).getHash(&breaks); return breaks;
} }
uint breaks; uint breaks;
private: private:
int _cost; int _cost;
int _depth;
bool _solved; bool _solved;
} }
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable short[] depths, size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
const Config* config, int currentLineLength, int indentLevel) immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
{ {
import std.container.rbtree : RedBlackTree; import std.container.rbtree : RedBlackTree;
import std.algorithm : filter, min; import std.algorithm : filter, min;
import core.bitop:popcnt; import core.bitop : popcnt;
static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe
{ {
@ -137,10 +148,9 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable sho
enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8; enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS); immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
int depth = 0;
auto open = new RedBlackTree!State; auto open = new RedBlackTree!State;
open.insert(State(0, tokens[0 .. tokensEnd], open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd],
depths[0 .. tokensEnd], depth, config, currentLineLength, indentLevel)); config, currentLineLength, indentLevel));
State lowest; State lowest;
while (!open.empty) while (!open.empty)
{ {
@ -152,8 +162,8 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable sho
{ {
return genRetVal(current.breaks, index); return genRetVal(current.breaks, index);
} }
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], validMoves!(typeof(open))(open, tokens[0 .. tokensEnd],
current.breaks, config, currentLineLength, indentLevel, depth); depths[0 .. tokensEnd], current.breaks, config, currentLineLength, indentLevel);
} }
if (open.empty) if (open.empty)
return genRetVal(lowest.breaks, index); return genRetVal(lowest.breaks, index);
@ -162,10 +172,10 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable sho
assert(false); assert(false);
} }
void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[] depths, void validMoves(OR)(auto ref OR output, const Token[] tokens,
uint current, const Config* config, int currentLineLength, int indentLevel, immutable short[] depths, uint current, const Config* config,
int depth) pure int currentLineLength, int indentLevel) pure
{ {
import std.algorithm : sort, canFind; import std.algorithm : sort, canFind;
import std.array : insertInPlace; import std.array : insertInPlace;
@ -174,7 +184,7 @@ void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[]
if (!isBreakToken(token.type) || (((1 << i) & current) != 0)) if (!isBreakToken(token.type) || (((1 << i) & current) != 0))
continue; continue;
immutable uint breaks = current | (1 << i); immutable uint breaks = current | (1 << i);
output.insert(State(breaks, tokens, depths, depth + 1, config, output.insert(State(breaks, tokens, depths, config,
currentLineLength, indentLevel)); currentLineLength, indentLevel));
} }
} }