This repository has been archived on 2022-04-04. You can view files and clone it, but cannot push or open issues or pull requests.

137 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Wrap abstract fragments into lines with a first-fit algorithm."><meta name="keywords" content="rust, rustlang, rust-lang, wrap_first_fit"><title>wrap_first_fit in textwrap::wrap_algorithms - Rust</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Regular.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Medium.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Bold.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Semibold.ttf.woff2"><link rel="stylesheet" type="text/css" href="../../normalize.css"><link rel="stylesheet" type="text/css" href="../../rustdoc.css" id="mainThemeStyle"><link rel="stylesheet" type="text/css" href="../../ayu.css" disabled><link rel="stylesheet" type="text/css" href="../../dark.css" disabled><link rel="stylesheet" type="text/css" href="../../light.css" id="themeStyle"><script id="default-settings" ></script><script src="../../storage.js"></script><script src="../../crates.js"></script><script defer src="../../main.js"></script>
<noscript><link rel="stylesheet" href="../../noscript.css"></noscript><link rel="alternate icon" type="image/png" href="../../favicon-16x16.png"><link rel="alternate icon" type="image/png" href="../../favicon-32x32.png"><link rel="icon" type="image/svg+xml" href="../../favicon.svg"></head><body class="rustdoc fn"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="sidebar-menu" role="button">&#9776;</div><a class="sidebar-logo" href="../../textwrap/index.html"><div class="logo-container"><img class="rust-logo" src="../../rust-logo.png" alt="logo"></div>
</a><div class="sidebar-elems"><h2 class="location">Other items in<br><a href="../index.html">textwrap</a>::<wbr><a href="index.html">wrap_algorithms</a></h2><div id="sidebar-vars" data-name="wrap_first_fit" data-ty="fn" data-relpath=""></div><script defer src="sidebar-items.js"></script></div></nav><main><div class="width-limiter"><div class="sub-container"><a class="sub-logo-container" href="../../textwrap/index.html"><img class="rust-logo" src="../../rust-logo.png" alt="logo"></a><nav class="sub"><div class="theme-picker"><button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"><img width="18" height="18" alt="Pick another theme!" src="../../brush.svg"></button><div id="theme-choices" role="menu"></div></div><form class="search-form"><div class="search-container"><div><select id="crate-search"><option value="All crates">All crates</option></select><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"></div><button type="button" id="help-button" title="help">?</button><a id="settings-menu" href="../../settings.html" title="settings"><img width="18" height="18" alt="Change settings" src="../../wheel.svg"></a></div></form></nav></div><section id="main-content" class="content"><h1 class="fqn"><span class="in-band">Function <a href="../index.html">textwrap</a>::<wbr><a href="index.html">wrap_algorithms</a>::<wbr><a class="fn" href="#">wrap_first_fit</a><button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"><img src="../../clipboard.svg" width="19" height="18" alt="Copy item path"></button></span><span class="out-of-band"><span id="render-detail"><a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">[<span class="inner">&#x2212;</span>]</a></span><a class="srclink" href="../../src/textwrap/wrap_algorithms.rs.html#315-339" title="goto source code">[src]</a></span></h1><div class="docblock item-decl"><pre class="rust fn"><code>pub fn wrap_first_fit&lt;'a, 'b, T:&nbsp;<a class="trait" href="../core/trait.Fragment.html" title="trait textwrap::core::Fragment">Fragment</a>&gt;(<br>&nbsp;&nbsp;&nbsp;&nbsp;fragments: <a class="primitive" href="https://doc.rust-lang.org/1.59.0/std/primitive.slice.html">&amp;'a [T]</a>, <br>&nbsp;&nbsp;&nbsp;&nbsp;line_widths: <a class="primitive" href="https://doc.rust-lang.org/1.59.0/std/primitive.slice.html">&amp;'b [</a><a class="primitive" href="https://doc.rust-lang.org/1.59.0/std/primitive.f64.html">f64</a><a class="primitive" href="https://doc.rust-lang.org/1.59.0/std/primitive.slice.html">]</a><br>) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.59.0/alloc/vec/struct.Vec.html" title="struct alloc::vec::Vec">Vec</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.59.0/std/primitive.slice.html">&amp;'a [T]</a>&gt;</code></pre></div><details class="rustdoc-toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Wrap abstract fragments into lines with a first-fit algorithm.</p>
<p>The <code>line_widths</code> slice gives the target line width for each line
(the last slice element is repeated as necessary). This can be
used to implement hanging indentation.</p>
<p>The fragments must already have been split into the desired
widths, this function will not (and cannot) attempt to split them
further when arranging them into lines.</p>
<h2 id="first-fit-algorithm" class="section-header"><a href="#first-fit-algorithm">First-Fit Algorithm</a></h2>
<p>This implements a simple “greedy” algorithm: accumulate fragments
one by one and when a fragment no longer fits, start a new line.
There is no look-ahead, we simply take first fit of the fragments
we find.</p>
<p>While fast and predictable, this algorithm can produce poor line
breaks when a long fragment is moved to a new line, leaving behind
a large gap:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use</span> <span class="ident">textwrap::core::Word</span>;
<span class="kw">use</span> <span class="ident">textwrap::wrap_algorithms::wrap_first_fit</span>;
<span class="kw">use</span> <span class="ident">textwrap::WordSeparator</span>;
<span class="comment">// Helper to convert wrapped lines to a Vec&lt;String&gt;.</span>
<span class="kw">fn</span> <span class="ident">lines_to_strings</span>(<span class="ident">lines</span>: <span class="ident">Vec</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>[<span class="ident">Word</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>]<span class="op">&gt;</span>) -&gt; <span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> {
<span class="ident">lines</span>.<span class="ident">iter</span>().<span class="ident">map</span>(<span class="op">|</span><span class="ident">line</span><span class="op">|</span> {
<span class="ident">line</span>.<span class="ident">iter</span>().<span class="ident">map</span>(<span class="op">|</span><span class="ident">word</span><span class="op">|</span> <span class="kw-2">&amp;</span><span class="kw-2">*</span><span class="kw-2">*</span><span class="ident">word</span>).<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>().<span class="ident">join</span>(<span class="string">&quot; &quot;</span>)
}).<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>()
}
<span class="kw">let</span> <span class="ident">text</span> <span class="op">=</span> <span class="string">&quot;These few words will unfortunately not wrap nicely.&quot;</span>;
<span class="kw">let</span> <span class="ident">words</span> <span class="op">=</span> <span class="ident">WordSeparator::AsciiSpace</span>.<span class="ident">find_words</span>(<span class="ident">text</span>).<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>();
<span class="macro">assert_eq!</span>(<span class="ident">lines_to_strings</span>(<span class="ident">wrap_first_fit</span>(<span class="kw-2">&amp;</span><span class="ident">words</span>, <span class="kw-2">&amp;</span>[<span class="number">15.0</span>])),
<span class="macro">vec!</span>[<span class="string">&quot;These few words&quot;</span>,
<span class="string">&quot;will&quot;</span>, <span class="comment">// &lt;-- short line</span>
<span class="string">&quot;unfortunately&quot;</span>,
<span class="string">&quot;not wrap&quot;</span>,
<span class="string">&quot;nicely.&quot;</span>]);
<span class="comment">// We can avoid the short line if we look ahead:</span>
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;smawk&quot;</span>)]</span>
<span class="kw">use</span> <span class="ident">textwrap::wrap_algorithms</span>::{<span class="ident">wrap_optimal_fit</span>, <span class="ident">Penalties</span>};
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;smawk&quot;</span>)]</span>
<span class="macro">assert_eq!</span>(<span class="ident">lines_to_strings</span>(<span class="ident">wrap_optimal_fit</span>(<span class="kw-2">&amp;</span><span class="ident">words</span>, <span class="kw-2">&amp;</span>[<span class="number">15.0</span>], <span class="kw-2">&amp;</span><span class="ident">Penalties::new</span>()).<span class="ident">unwrap</span>()),
<span class="macro">vec!</span>[<span class="string">&quot;These few&quot;</span>,
<span class="string">&quot;words will&quot;</span>,
<span class="string">&quot;unfortunately&quot;</span>,
<span class="string">&quot;not wrap&quot;</span>,
<span class="string">&quot;nicely.&quot;</span>]);</code></pre></div>
<p>The [<code>wrap_optimal_fit</code>] function was used above to get better
line breaks. It uses an advanced algorithm which tries to avoid
short lines. This function is about 4 times faster than
[<code>wrap_optimal_fit</code>].</p>
<h2 id="examples" class="section-header"><a href="#examples">Examples</a></h2>
<p>Imagine youre building a house site and you have a number of
tasks you need to execute. Things like pour foundation, complete
framing, install plumbing, electric cabling, install insulation.</p>
<p>The construction workers can only work during daytime, so they
need to pack up everything at night. Because they need to secure
their tools and move machines back to the garage, this process
takes much more time than the time it would take them to simply
switch to another task.</p>
<p>You would like to make a list of tasks to execute every day based
on your estimates. You can model this with a program like this:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use</span> <span class="ident">textwrap::core</span>::{<span class="ident">Fragment</span>, <span class="ident">Word</span>};
<span class="kw">use</span> <span class="ident">textwrap::wrap_algorithms::wrap_first_fit</span>;
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Debug</span>)]</span>
<span class="kw">struct</span> <span class="ident">Task</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> {
<span class="ident">name</span>: <span class="kw-2">&amp;</span><span class="lifetime">&#39;a</span> <span class="ident">str</span>,
<span class="ident">hours</span>: <span class="ident">f64</span>, <span class="comment">// Time needed to complete task.</span>
<span class="ident">sweep</span>: <span class="ident">f64</span>, <span class="comment">// Time needed for a quick sweep after task during the day.</span>
<span class="ident">cleanup</span>: <span class="ident">f64</span>, <span class="comment">// Time needed for full cleanup if day ends with this task.</span>
}
<span class="kw">impl</span> <span class="ident">Fragment</span> <span class="kw">for</span> <span class="ident">Task</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span> {
<span class="kw">fn</span> <span class="ident">width</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">f64</span> { <span class="self">self</span>.<span class="ident">hours</span> }
<span class="kw">fn</span> <span class="ident">whitespace_width</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">f64</span> { <span class="self">self</span>.<span class="ident">sweep</span> }
<span class="kw">fn</span> <span class="ident">penalty_width</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">f64</span> { <span class="self">self</span>.<span class="ident">cleanup</span> }
}
<span class="comment">// The morning tasks</span>
<span class="kw">let</span> <span class="ident">tasks</span> <span class="op">=</span> <span class="macro">vec!</span>[
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Foundation&quot;</span>, <span class="ident">hours</span>: <span class="number">4.0</span>, <span class="ident">sweep</span>: <span class="number">2.0</span>, <span class="ident">cleanup</span>: <span class="number">3.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Framing&quot;</span>, <span class="ident">hours</span>: <span class="number">3.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Plumbing&quot;</span>, <span class="ident">hours</span>: <span class="number">2.0</span>, <span class="ident">sweep</span>: <span class="number">2.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Electrical&quot;</span>, <span class="ident">hours</span>: <span class="number">2.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Insulation&quot;</span>, <span class="ident">hours</span>: <span class="number">2.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Drywall&quot;</span>, <span class="ident">hours</span>: <span class="number">3.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Floors&quot;</span>, <span class="ident">hours</span>: <span class="number">3.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Countertops&quot;</span>, <span class="ident">hours</span>: <span class="number">1.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
<span class="ident">Task</span> { <span class="ident">name</span>: <span class="string">&quot;Bathrooms&quot;</span>, <span class="ident">hours</span>: <span class="number">2.0</span>, <span class="ident">sweep</span>: <span class="number">1.0</span>, <span class="ident">cleanup</span>: <span class="number">2.0</span> },
];
<span class="comment">// Fill tasks into days, taking `day_length` into account. The</span>
<span class="comment">// output shows the hours worked per day along with the names of</span>
<span class="comment">// the tasks for that day.</span>
<span class="kw">fn</span> <span class="ident">assign_days</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span>(<span class="ident">tasks</span>: <span class="kw-2">&amp;</span>[<span class="ident">Task</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span>], <span class="ident">day_length</span>: <span class="ident">f64</span>) -&gt; <span class="ident">Vec</span><span class="op">&lt;</span>(<span class="ident">f64</span>, <span class="ident">Vec</span><span class="op">&lt;</span><span class="kw-2">&amp;</span><span class="lifetime">&#39;a</span> <span class="ident">str</span><span class="op">&gt;</span>)<span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">days</span> <span class="op">=</span> <span class="ident">Vec::new</span>();
<span class="comment">// Assign tasks to days. The assignment is a vector of slices,</span>
<span class="comment">// with a slice per day.</span>
<span class="kw">let</span> <span class="ident">assigned_days</span>: <span class="ident">Vec</span><span class="op">&lt;</span><span class="kw-2">&amp;</span>[<span class="ident">Task</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span>]<span class="op">&gt;</span> <span class="op">=</span> <span class="ident">wrap_first_fit</span>(<span class="kw-2">&amp;</span><span class="ident">tasks</span>, <span class="kw-2">&amp;</span>[<span class="ident">day_length</span>]);
<span class="kw">for</span> <span class="ident">day</span> <span class="kw">in</span> <span class="ident">assigned_days</span>.<span class="ident">iter</span>() {
<span class="kw">let</span> <span class="ident">last</span> <span class="op">=</span> <span class="ident">day</span>.<span class="ident">last</span>().<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">work_hours</span>: <span class="ident">f64</span> <span class="op">=</span> <span class="ident">day</span>.<span class="ident">iter</span>().<span class="ident">map</span>(<span class="op">|</span><span class="ident">t</span><span class="op">|</span> <span class="ident">t</span>.<span class="ident">hours</span> <span class="op">+</span> <span class="ident">t</span>.<span class="ident">sweep</span>).<span class="ident">sum</span>();
<span class="kw">let</span> <span class="ident">names</span> <span class="op">=</span> <span class="ident">day</span>.<span class="ident">iter</span>().<span class="ident">map</span>(<span class="op">|</span><span class="ident">t</span><span class="op">|</span> <span class="ident">t</span>.<span class="ident">name</span>).<span class="ident">collect</span>::<span class="op">&lt;</span><span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span><span class="op">&gt;</span>();
<span class="ident">days</span>.<span class="ident">push</span>((<span class="ident">work_hours</span> <span class="op">-</span> <span class="ident">last</span>.<span class="ident">sweep</span> <span class="op">+</span> <span class="ident">last</span>.<span class="ident">cleanup</span>, <span class="ident">names</span>));
}
<span class="ident">days</span>
}
<span class="comment">// With a single crew working 8 hours a day:</span>
<span class="macro">assert_eq!</span>(
<span class="ident">assign_days</span>(<span class="kw-2">&amp;</span><span class="ident">tasks</span>, <span class="number">8.0</span>),
[
(<span class="number">7.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Foundation&quot;</span>]),
(<span class="number">8.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Framing&quot;</span>, <span class="string">&quot;Plumbing&quot;</span>]),
(<span class="number">7.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Electrical&quot;</span>, <span class="string">&quot;Insulation&quot;</span>]),
(<span class="number">5.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Drywall&quot;</span>]),
(<span class="number">7.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Floors&quot;</span>, <span class="string">&quot;Countertops&quot;</span>]),
(<span class="number">4.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Bathrooms&quot;</span>]),
]
);
<span class="comment">// With two crews working in shifts, 16 hours a day:</span>
<span class="macro">assert_eq!</span>(
<span class="ident">assign_days</span>(<span class="kw-2">&amp;</span><span class="ident">tasks</span>, <span class="number">16.0</span>),
[
(<span class="number">14.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Foundation&quot;</span>, <span class="string">&quot;Framing&quot;</span>, <span class="string">&quot;Plumbing&quot;</span>]),
(<span class="number">15.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Electrical&quot;</span>, <span class="string">&quot;Insulation&quot;</span>, <span class="string">&quot;Drywall&quot;</span>, <span class="string">&quot;Floors&quot;</span>]),
(<span class="number">6.0</span>, <span class="macro">vec!</span>[<span class="string">&quot;Countertops&quot;</span>, <span class="string">&quot;Bathrooms&quot;</span>]),
]
);</code></pre></div>
<p>Apologies to anyone who actually knows how to build a house and
knows how long each step takes :-)</p>
</div></details></section><section id="search" class="content hidden"></section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="textwrap" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.59.0 (9d1b2106e 2022-02-23)" ></div>
</body></html>