@@ -240,6 +240,52 @@ pub struct Histogram<T: Counter> {
240
240
counts : Vec < T > ,
241
241
}
242
242
243
+ /// Errors that can occur when creating a histogram.
244
+ #[ derive( Debug , Eq , PartialEq , Clone , Copy ) ]
245
+ pub enum CreationError {
246
+ /// Lowest discernible value must be >= 1.
247
+ LowIsZero ,
248
+ /// Lowest discernible value must be <= `u64::max_value() / 2` because the highest value is
249
+ /// a `u64` and the lowest value must be no bigger than half the highest.
250
+ LowExceedsMax ,
251
+ /// Highest trackable value must be >= 2 * lowest discernible value for some internal
252
+ /// calculations to work out. In practice, high is typically much higher than 2 * low.
253
+ HighLessThanTwiceLow ,
254
+ /// Number of significant digits must be in the range `[0, 5]`. It is capped at 5 because 5
255
+ /// significant digits is already more than almost anyone needs, and memory usage scales
256
+ /// exponentially as this increases.
257
+ SigFigExceedsMax ,
258
+ /// Cannot represent sigfig worth of values beyond the lowest discernible value. Decrease the
259
+ /// significant figures, lowest discernible value, or both.
260
+ ///
261
+ /// This could happen if low is very large (like 2^60) and sigfigs is 5, which requires 18
262
+ /// additional bits, which would then require more bits than will fit in a u64. Specifically,
263
+ /// the exponent of the largest power of two that is smaller than the lowest value and the bits
264
+ /// needed to represent the requested significant figures must sum to 63 or less.
265
+ CannotRepresentSigFigBeyondLow
266
+ }
267
+
268
+ /// Errors that can occur when adding another histogram.
269
+ #[ derive( Debug , Eq , PartialEq , Clone , Copy ) ]
270
+ pub enum AdditionError {
271
+ /// The other histogram includes values that do not fit in this histogram's range.
272
+ /// Only possible when auto resize is disabled.
273
+ OtherAddendValuesExceedRange
274
+ }
275
+
276
+ /// Errors that can occur when subtracting another histogram.
277
+ #[ derive( Debug , Eq , PartialEq , Clone , Copy ) ]
278
+ pub enum SubtractionError {
279
+ /// The other histogram includes values that do not fit in this histogram's range.
280
+ /// Only possible when auto resize is disabled.
281
+ SubtrahendValuesExceedMinuendRange ,
282
+ /// The other histogram includes counts that are higher than the current count for a value, and
283
+ /// counts cannot go negative. The subtraction may have been partially applied to some counts as
284
+ /// this error is returned when the first impossible subtraction is detected.
285
+ SubtrahendCountExceedsMinuendCount
286
+ }
287
+
288
+
243
289
/// Module containing the implementations of all `Histogram` iterators.
244
290
pub mod iterators;
245
291
@@ -356,7 +402,7 @@ impl<T: Counter> Histogram<T> {
356
402
357
403
/// Overwrite this histogram with the given histogram. All data and statistics in this
358
404
/// histogram will be overwritten.
359
- pub fn set_to < B : Borrow < Histogram < T > > > ( & mut self , source : B ) -> Result < ( ) , & ' static str > {
405
+ pub fn set_to < B : Borrow < Histogram < T > > > ( & mut self , source : B ) -> Result < ( ) , AdditionError > {
360
406
self . reset ( ) ;
361
407
self . add ( source. borrow ( ) )
362
408
}
@@ -380,15 +426,14 @@ impl<T: Counter> Histogram<T> {
380
426
///
381
427
/// May fail if values in the other histogram are higher than `.high()`, and auto-resize is
382
428
/// disabled.
383
- pub fn add < B : Borrow < Histogram < T > > > ( & mut self , source : B ) -> Result < ( ) , & ' static str > {
429
+ pub fn add < B : Borrow < Histogram < T > > > ( & mut self , source : B ) -> Result < ( ) , AdditionError > {
384
430
let source = source. borrow ( ) ;
385
431
386
432
// make sure we can take the values in source
387
433
let top = self . highest_equivalent ( self . value_for ( self . last ( ) ) ) ;
388
434
if top < source. max ( ) {
389
435
if !self . auto_resize {
390
- return Err ( "The other histogram includes values that do not fit in this \
391
- histogram's range.") ;
436
+ return Err ( AdditionError :: OtherAddendValuesExceedRange ) ;
392
437
}
393
438
self . resize ( source. max ( ) ) ;
394
439
}
@@ -480,15 +525,14 @@ impl<T: Counter> Histogram<T> {
480
525
/// disabled. Or, if the count for a given value in the other histogram is higher than that of
481
526
/// this histogram. In the latter case, some of the counts may still have been updated, which
482
527
/// may cause data corruption.
483
- pub fn subtract < B : Borrow < Histogram < T > > > ( & mut self , other : B ) -> Result < ( ) , & ' static str > {
528
+ pub fn subtract < B : Borrow < Histogram < T > > > ( & mut self , other : B ) -> Result < ( ) , SubtractionError > {
484
529
let other = other. borrow ( ) ;
485
530
486
531
// make sure we can take the values in source
487
532
let top = self . highest_equivalent ( self . value_for ( self . last ( ) ) ) ;
488
533
if top < other. max ( ) {
489
534
if !self . auto_resize {
490
- return Err ( "The other histogram includes values that do not fit in this \
491
- histogram's range.") ;
535
+ return Err ( SubtractionError :: SubtrahendValuesExceedMinuendRange ) ;
492
536
}
493
537
self . resize ( other. max ( ) ) ;
494
538
}
@@ -498,8 +542,7 @@ impl<T: Counter> Histogram<T> {
498
542
if other_count != T :: zero ( ) {
499
543
let other_value = other. value_for ( i) ;
500
544
if self . count_at ( other_value) . unwrap ( ) < other_count {
501
- return Err ( "The other histogram includes counts that are higher than the \
502
- current count for that value.") ;
545
+ return Err ( SubtractionError :: SubtrahendCountExceedsMinuendCount ) ;
503
546
}
504
547
self . alter_n ( other_value, other_count, false ) . expect ( "value should fit by now" ) ;
505
548
}
@@ -553,10 +596,10 @@ impl<T: Counter> Histogram<T> {
553
596
/// auto-adjusting highest trackable value. Can auto-resize up to track values up to
554
597
/// `(i64::max_value() / 2)`.
555
598
///
556
- /// `sigfig` specifies the number of significant value digits to preserve in the recorded data .
557
- /// This is the number of significant decimal digits to which the histogram will maintain value
558
- /// resolution and separation. Must be a non-negative integer between 0 and 5.
559
- pub fn new ( sigfig : u8 ) -> Result < Histogram < T > , & ' static str > {
599
+ /// See [`new_with_bounds`] for info on `sigfig` .
600
+ ///
601
+ /// [`new_with_bounds`]: #method.new_with_bounds
602
+ pub fn new ( sigfig : u8 ) -> Result < Histogram < T > , CreationError > {
560
603
let mut h = Self :: new_with_bounds ( 1 , 2 , sigfig) ;
561
604
if let Ok ( ref mut h) = h {
562
605
h. auto_resize = true ;
@@ -568,41 +611,45 @@ impl<T: Counter> Histogram<T> {
568
611
/// significant decimal digits. The histogram will be constructed to implicitly track
569
612
/// (distinguish from 0) values as low as 1. Auto-resizing will be disabled.
570
613
///
571
- /// `high` is the highest value to be tracked by the histogram, and must be a positive integer
572
- /// that is >= 2. `sigfig` specifies the number of significant figures to maintain. This is the
573
- /// number of significant decimal digits to which the histogram will maintain value resolution
574
- /// and separation. Must be a non-negative integer between 0 and 5.
575
- pub fn new_with_max ( high : u64 , sigfig : u8 ) -> Result < Histogram < T > , & ' static str > {
614
+ /// See [`new_with_bounds`] for info on `high` and `sigfig`.
615
+ ///
616
+ /// [`new_with_bounds`]: #method.new_with_bounds
617
+ pub fn new_with_max ( high : u64 , sigfig : u8 ) -> Result < Histogram < T > , CreationError > {
576
618
Self :: new_with_bounds ( 1 , high, sigfig)
577
619
}
578
620
579
621
/// Construct a `Histogram` with known upper and lower bounds for recorded sample values.
580
- /// Providing a lowest discernible value (`low`) is useful is situations where the units used
581
- /// for the histogram's values are much smaller that the minimal accuracy required. E.g. when
582
- /// tracking time values stated in nanosecond units, where the minimal accuracy required is a
583
- /// microsecond, the proper value for `low` would be 1000.
584
622
///
585
623
/// `low` is the lowest value that can be discerned (distinguished from 0) by the histogram,
586
624
/// and must be a positive integer that is >= 1. It may be internally rounded down to nearest
587
- /// power of 2. `high` is the highest value to be tracked by the histogram, and must be a
588
- /// positive integer that is `>= (2 * low)`. `sigfig` Specifies the number of significant
589
- /// figures to maintain. This is the number of significant decimal digits to which the
590
- /// histogram will maintain value resolution and separation. Must be a non-negative integer
591
- /// between 0 and 5.
592
- pub fn new_with_bounds ( low : u64 , high : u64 , sigfig : u8 ) -> Result < Histogram < T > , & ' static str > {
625
+ /// power of 2. Providing a lowest discernible value (`low`) is useful is situations where the
626
+ /// units used for the histogram's values are much smaller that the minimal accuracy required.
627
+ /// E.g. when tracking time values stated in nanosecond units, where the minimal accuracy
628
+ /// required is a microsecond, the proper value for `low` would be 1000. If you're not sure,
629
+ /// use 1.
630
+ ///
631
+ /// `high` is the highest value to be tracked by the histogram, and must be a
632
+ /// positive integer that is `>= (2 * low)`. If you're not sure, use `u64::max_value()`.
633
+ ///
634
+ /// `sigfig` Specifies the number of significant figures to maintain. This is the number of
635
+ /// significant decimal digits to which the histogram will maintain value resolution and
636
+ /// separation. Must be in the range [0, 5]. If you're not sure, use 3. As `sigfig` increases,
637
+ /// memory usage grows exponentially, so choose carefully if there will be many histograms in
638
+ /// memory at once or if storage is otherwise a concern.
639
+ pub fn new_with_bounds ( low : u64 , high : u64 , sigfig : u8 ) -> Result < Histogram < T > , CreationError > {
593
640
// Verify argument validity
594
641
if low < 1 {
595
- return Err ( "lowest discernible value must be >= 1" ) ;
642
+ return Err ( CreationError :: LowIsZero ) ;
596
643
}
597
644
if low > u64:: max_value ( ) / 2 {
598
645
// avoid overflow in 2 * low
599
- return Err ( "lowest discernible value must be <= u64::max_value() / 2" )
646
+ return Err ( CreationError :: LowExceedsMax )
600
647
}
601
648
if high < 2 * low {
602
- return Err ( "highest trackable value must be >= 2 * lowest discernible value" ) ;
649
+ return Err ( CreationError :: HighLessThanTwiceLow ) ;
603
650
}
604
651
if sigfig > 5 {
605
- return Err ( "number of significant digits must be between 0 and 5" ) ;
652
+ return Err ( CreationError :: SigFigExceedsMax ) ;
606
653
}
607
654
608
655
// Given a 3 decimal point accuracy, the expectation is obviously for "+/- 1 unit at 1000".
@@ -634,7 +681,7 @@ impl<T: Counter> Histogram<T> {
634
681
// histogram vs ones whose magnitude here fits in 63 bits is debatable, and it makes
635
682
// it harder to work through the logic. Sums larger than 64 are totally broken as
636
683
// leading_zero_count_base would go negative.
637
- return Err ( "Cannot represent sigfig worth of values beyond low" ) ;
684
+ return Err ( CreationError :: CannotRepresentSigFigBeyondLow ) ;
638
685
} ;
639
686
640
687
let sub_bucket_half_count = sub_bucket_count / 2 ;
0 commit comments