aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/yt/string/format.h
blob: d15127fae0565ceaed8af13222f496784ca73b76 (plain) (tree)
1
2
3
4
5
6
7
8
9
            
                          
                           
                                
 
                   







                                                                                
  


                                                                   
  
                                                                                          
  
                                                                                  
  
                                                                        
  
                                                                        
  
                                                       
  
                                               
  
                                                                             
                        
  
                                                 
  
                                                                                         
  

                                                                               
  
                                          
  



                                             
                         
                                                                

                                                                                








                                                                                          
                                         
                       
 



                                                                                
                         
                                                      

                         


                                                                        
                                                         
                        
                            
 
                                         
                                                               
                        
                           


                                                                                























































                                                                                       




                           

                                          
            

                                              
                                   



                                                             




                                                                                





                                                    
                         












                                                                                    
                                                                 






                                                                

                                              
                             





                                     
                                                                    










                                                                                
                                 



                                
                      


                                       
                                 


                        
                      
                        

                                                                                



                       
#pragma once

#include "format_string.h"
#include "string_builder.h"

#include <util/generic/string.h>

#include <iterator>

namespace NYT {

////////////////////////////////////////////////////////////////////////////////

/*
 *  Format: a type-safe and fast formatting utility.
 *
 *  Basically works as a type-safe analogue of |sprintf| and is expected to
 *  be backwards-compatible with the latter.
 *
 *  Like Go's |Sprintf|, supports the ultimate format specifier |v|
 *  causing arguments to be emitted in default format.
 *  This is the default and preferred way of formatting things,
 *  which should be used in newer code.
 *
 *  |Format| may currently invoke |sprintf| internally for emitting numeric and some other
 *  types. You can always write your own optimized implementation, if you wish :)
 *
 *  In additional to the usual |sprintf|, supports a number of non-standard flags:
 *
 *  |q|   Causes the argument to be surrounded with single quotes (|'|).
 *        Applies to all types.
 *
 *  |Q|   Causes the argument to be surrounded with double quotes (|"|).
 *        Applies to all types.
 *
 *  |l|   The argument is emitted in "lowercase" style.
 *        Only applies to enums and bools.
 *
 *  The following argument types are supported:
 *
 *  Strings (including |const char*|, |TStringBuf|, and |TString|) and chars:
 *  Emitted as is. Fast.
 *
 *  Numerics and pointers:
 *  Emitted using |sprintf|. Maybe not that fast.
 *
 *  |bool|:
 *  Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON).
 *
 *  Enums:
 *  Emitted in either camel (|SomeName|) or in lowercase-with-underscores style
 *  (|some_name|, if lowercase mode is ON).
 *
 *  Nullables:
 *  |std::nullopt| is emitted as |<null>|.
 *
 *  All others:
 *  Emitted as strings by calling |ToString|.
 *
 */

template <class... TArgs>
TString Format(TFormatString<TArgs...> format, TArgs&&... args);

////////////////////////////////////////////////////////////////////////////////

template <class... TArgs>
void Format(TStringBuilderBase* builder, TFormatString<TArgs...> format, TArgs&&... args);

////////////////////////////////////////////////////////////////////////////////

template <class T>
TString ToStringViaBuilder(const T& value, TStringBuf spec = TStringBuf("v"));

////////////////////////////////////////////////////////////////////////////////

template <class TRange, class TFormatter>
struct TFormattableView
{
    using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>;
    using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>;

    TBegin RangeBegin;
    TEnd RangeEnd;
    TFormatter Formatter;
    size_t Limit = std::numeric_limits<size_t>::max();

    TBegin begin() const;
    TEnd end() const;
};

//! Annotates a given #range with #formatter to be applied to each item.
template <class TRange, class TFormatter>
TFormattableView<TRange, TFormatter> MakeFormattableView(
    const TRange& range,
    TFormatter&& formatter);

template <class TRange, class TFormatter>
TFormattableView<TRange, TFormatter> MakeShrunkFormattableView(
    const TRange& range,
    TFormatter&& formatter,
    size_t limit);

////////////////////////////////////////////////////////////////////////////////

template <class TRange, class TValueGetter, class TIntervalFormatter>
struct TCompactIntervalView
{
    using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>;
    using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>;

    TBegin RangeBegin;
    TEnd RangeEnd;

    TValueGetter ValueGetter;
    TIntervalFormatter IntervalFormatter;

    TBegin begin() const;
    TEnd end() const;
};

template <class TRange>
struct TDefaultValueGetter
{
    using TIterator = std::decay_t<decltype(std::declval<const TRange>().begin())>;

    auto operator()(const TIterator& iterator) const
        -> typename std::iterator_traits<TIterator>::value_type;
};

template <class TRange, class TValueGetter>
struct TDefaultIntervalFormatter
{
    using TIterator = std::decay_t<decltype(std::declval<const TRange>().begin())>;

    void operator()(
        TStringBuilderBase* builder,
        const TIterator& first,
        const TIterator& last,
        const TValueGetter& valueGetter,
        bool firstInterval) const;
};

////////////////////////////////////////////////////////////////////////////////

//! Writes a given integral #range as a sequence of intervals.
//! Example:
// MakeCompactIntervalView(std::vector {1, 2, 3, 5, 7, 8})
// => [1-3,5,7-8]

template <
    class TRange,
    class TValueGetter = TDefaultValueGetter<TRange>,
    class TIntervalFormatter = TDefaultIntervalFormatter<TRange, TValueGetter>
>
TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter> MakeCompactIntervalView(
    const TRange& range,
    TValueGetter&& valueGetter = {},
    TIntervalFormatter&& intervalFormatter = {});

////////////////////////////////////////////////////////////////////////////////

template <class TFormatter>
struct TFormatterWrapper
{
    TFormatter Formatter;
};

// Allows insertion of text conditionally.
// Usage:
/*
NYT::Format(
    "Value is %v%v",
    42,
    MakeFormatterWrapper([&] (auto* builder) {
        if (PossiblyMissingInfo_) {
            builder->AppendString(", PossiblyMissingInfo: ");
            FormatValue(builder, PossiblyMissingInfo_, "v");
        }
    }));
 */
template <class TFormatter>
TFormatterWrapper<TFormatter> MakeFormatterWrapper(
    TFormatter&& formatter);

////////////////////////////////////////////////////////////////////////////////

template <class... TArgs>
class TLazyMultiValueFormatter;

template <class... TArgs>
void FormatValue(
    TStringBuilderBase* builder,
    const TLazyMultiValueFormatter<TArgs...>& value,
    TStringBuf /*spec*/);

//! A wrapper for a bunch of values that formats them lazily on demand.
/*!
 *  The intended use of this class is when you need to use the same formatted string
 *  in several places in the function (e.g. log message tags) and want both to avoid
 *  code duplication and premature formatting of the values until necessary.
 *
 *  NB: lvalues are captured by reference without lifetime extension.
 */
template <class... TArgs>
class TLazyMultiValueFormatter
    : private TNonCopyable
{
public:
    TLazyMultiValueFormatter(TStringBuf format, TArgs&&... args);

    // NB(arkady-e1ppa): We actually have to
    // forward declare this method as above
    // and friend-declare it as specialization
    // here because clang is stupid and would
    // treat this friend declartion as a hidden friend
    // declaration which in turn is treated as a separate symbol
    // causing linker to not find the actual definition.
    friend void FormatValue<>(
        TStringBuilderBase* builder,
        const TLazyMultiValueFormatter& value,
        TStringBuf /*spec*/);

private:
    const TStringBuf Format_;
    const std::tuple<TArgs...> Args_;
};

template <class ... Args>
auto MakeLazyMultiValueFormatter(TStringBuf format, Args&&... args);

////////////////////////////////////////////////////////////////////////////////

/*
    Example:

    FormatVector("One: %v, Two: %v, Three: %v", {1, 2, 3})
    => "One: 1, Two: 2, Three: 3"
*/
template <size_t Length, class TVector>
void FormatVector(
    TStringBuilderBase* builder,
    const char (&format)[Length],
    const TVector& vec);

template <class TVector>
void FormatVector(
    TStringBuilderBase* builder,
    TStringBuf format,
    const TVector& vec);

template <size_t Length, class TVector>
TString FormatVector(
    const char (&format)[Length],
    const TVector& vec);

template <class TVector>
TString FormatVector(
    TStringBuf format,
    const TVector& vec);

////////////////////////////////////////////////////////////////////////////////

} // namespace NYT

#define FORMAT_INL_H_
#include "format-inl.h"
#undef FORMAT_INL_H_