@@ -248,7 +248,8 @@ impl Dimensions {
248
248
pub struct Grid {
249
249
options : GridOptions ,
250
250
cells : Vec < Cell > ,
251
- widest_cell_length : Width ,
251
+ widest_cell_width : Width ,
252
+ narrowest_cell_width : Width ,
252
253
width_sum : Width ,
253
254
cell_count : usize ,
254
255
}
@@ -258,7 +259,8 @@ impl Grid {
258
259
/// Creates a new grid view with the given options.
259
260
pub fn new ( options : GridOptions ) -> Self {
260
261
let cells = Vec :: new ( ) ;
261
- Self { options, cells, widest_cell_length : 0 ,
262
+ Self { options, cells,
263
+ widest_cell_width : 0 , narrowest_cell_width : usize:: MAX ,
262
264
width_sum : 0 , cell_count : 0 }
263
265
}
264
266
@@ -270,8 +272,11 @@ impl Grid {
270
272
271
273
/// Adds another cell onto the vector.
272
274
pub fn add ( & mut self , cell : Cell ) {
273
- if cell. width > self . widest_cell_length {
274
- self . widest_cell_length = cell. width ;
275
+ if cell. width > self . widest_cell_width {
276
+ self . widest_cell_width = cell. width ;
277
+ }
278
+ if cell. width < self . narrowest_cell_width {
279
+ self . narrowest_cell_width = cell. width ;
275
280
}
276
281
self . width_sum += cell. width ;
277
282
self . cell_count += 1 ;
@@ -322,36 +327,8 @@ impl Grid {
322
327
Dimensions { num_lines, widths }
323
328
}
324
329
325
- fn theoretical_max_num_lines ( & self , maximum_width : usize ) -> usize {
326
- // TODO: Make code readable / efficient.
327
- let mut theoretical_min_num_cols = 0 ;
328
- let mut col_total_width_so_far = 0 ;
329
-
330
- let mut cells = self . cells . clone ( ) ;
331
- cells. sort_unstable_by ( |a, b| b. width . cmp ( & a. width ) ) ; // Sort in reverse order
332
-
333
- for cell in & cells {
334
- if cell. width + col_total_width_so_far <= maximum_width {
335
- theoretical_min_num_cols += 1 ;
336
- col_total_width_so_far += cell. width ;
337
- } else {
338
- let mut theoretical_max_num_lines = self . cell_count / theoretical_min_num_cols;
339
- if self . cell_count % theoretical_min_num_cols != 0 {
340
- theoretical_max_num_lines += 1 ;
341
- }
342
- return theoretical_max_num_lines;
343
- }
344
- col_total_width_so_far += self . options . filling . width ( )
345
- }
346
-
347
- // If we make it to this point, we have exhausted all cells before
348
- // reaching the maximum width; the theoretical max number of lines
349
- // needed to display all cells is 1.
350
- 1
351
- }
352
-
353
330
fn width_dimensions ( & self , maximum_width : Width ) -> Option < Dimensions > {
354
- if self . widest_cell_length > maximum_width {
331
+ if self . widest_cell_width > maximum_width {
355
332
// Largest cell is wider than maximum width; it is impossible to fit.
356
333
return None ;
357
334
}
@@ -370,51 +347,29 @@ impl Grid {
370
347
return None ;
371
348
}
372
349
373
- let theoretical_max_num_lines = self . theoretical_max_num_lines ( maximum_width) ;
374
- if theoretical_max_num_lines == 1 {
375
- // This if—statement is neccesary for the function to work correctly
376
- // for small inputs.
377
- return Some ( Dimensions {
378
- num_lines : 1 ,
379
- // I clone self.cells twice. Once here, and once in
380
- // self.theoretical_max_num_lines. Perhaps not the best for
381
- // performance?
382
- widths : self . cells . clone ( ) . into_iter ( ) . map ( |cell| cell. width ) . collect ( )
383
- } ) ;
384
- }
385
- // Instead of numbers of columns, try to find the fewest number of *lines*
386
- // that the output will fit in.
387
- let mut smallest_dimensions_yet = None ;
388
- for num_lines in ( 1 ..= theoretical_max_num_lines) . rev ( ) {
389
- // The number of columns is the number of cells divided by the number
390
- // of lines, *rounded up*.
391
- let num_columns = if self . cell_count % num_lines == 0 {
392
- self . cell_count / num_lines
393
- } else {
394
- self . cell_count / num_lines + 1
395
- } ;
350
+ let max_column_count = self . theoretical_max_column_count ( maximum_width) ;
351
+ for num_columns in ( 2 ..=max_column_count) . rev ( ) {
352
+ let potential_dimensions = self . columns_dimensions ( num_columns) ;
396
353
397
- // Early abort: if there are so many columns that the width of the
398
- // *column separators* is bigger than the width of the screen, then
399
- // don’t even try to tabulate it.
400
- // This is actually a necessary check, because the width is stored as
401
- // a usize, and making it go negative makes it huge instead, but it
402
- // also serves as a speed-up.
403
354
let total_separator_width = ( num_columns - 1 ) * self . options . filling . width ( ) ;
404
- if maximum_width < total_separator_width {
405
- continue ;
406
- }
407
-
408
- // Remove the separator width from the available space.
409
355
let adjusted_width = maximum_width - total_separator_width;
410
356
411
- let potential_dimensions = self . column_widths ( num_lines, num_columns) ;
412
357
if potential_dimensions. widths . iter ( ) . sum :: < Width > ( ) < adjusted_width {
413
358
return Some ( potential_dimensions) ;
414
359
}
415
360
}
416
361
417
- smallest_dimensions_yet
362
+ Some ( self . columns_dimensions ( 1 ) )
363
+ }
364
+
365
+ fn theoretical_max_column_count ( & self , maximum_width : Width ) -> usize {
366
+ // Best case: every column is of narrowest width, except the column with the widest cell
367
+ let max_column_count = ( ( maximum_width - self . widest_cell_width ) /
368
+ // let’s see how many filling + narrowest cells we can fit
369
+ ( self . narrowest_cell_width + self . options . filling . width ( ) )
370
+ ) + 1 ; // we add one since we substracted self.widest_cell_width at the beginning
371
+
372
+ return usize:: min ( max_column_count, self . cell_count ) ;
418
373
}
419
374
}
420
375
@@ -766,7 +721,7 @@ mod test {
766
721
grid. add ( Cell :: from ( * s) ) ;
767
722
}
768
723
769
- let bits = "test1||test2||test3||test4 ||test5 ||test6\n test7||test8||test9||test10 ||test11||\n " ;
724
+ let bits = "test1 ||test2 ||test3||test4||test5||test6||test7||test8||test9 \n test10 ||test11||\n " ;
770
725
assert_eq ! ( grid. fit_into_width( 69 ) . unwrap( ) . to_string( ) , bits) ;
771
726
assert_eq ! ( grid. fit_into_width( 69 ) . unwrap( ) . row_count( ) , 2 ) ;
772
727
}
0 commit comments