Advertisement
chadjoan

Function forwarding use-case: stringize() -> toString()

Jul 31st, 2020
4,471
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 5.37 KB | None | 0 0
  1. /// *slurping noises*
  2. interface StringVacuum :
  3.     OutputRange!string, OutputRange!wstring, OutputRange!dstring,
  4.     OutputRange!char,   OutputRange!wchar,   OutputRange!dchar
  5. {
  6.     void put(string  plainText);
  7.     void put(wstring plainText);
  8.     void put(dstring plainText);
  9.  
  10.     void put(char  oneChar);
  11.     void put(wchar oneChar);
  12.     void put(dchar oneChar);
  13. }
  14.  
  15. /// Woof.
  16. struct DogType
  17. {
  18.     string[4] whatAmI = ["I","am","a","dog"];
  19.  
  20.     /// The `stringize` method allows a type to convert itself to a string
  21.     /// without forcing the caller to endure less-than-deterministic behavior
  22.     /// such as GC allocations.
  23.     ///
  24.     /// How /actually/ @nogc this method /really is/ completely depends on
  25.     /// the StringVacuum implementation that the caller supplies.
  26.     ///
  27.     /// Regardless, this type's author has already done their own due-diligence,
  28.     /// and it is thus /possible/ to write an @nogc program that uses
  29.     /// the DogType and requires the ability to convert DogTypes to strings.
  30.     ///
  31.     @nogc nothrow void stringize(return scope StringVacuum writer)
  32.     {
  33.         size_t i = 0;
  34.         if ( i < whatAmI.length )
  35.             writer.send(this.whatAmI[i++]);
  36.  
  37.         for(; i < whatAmI.length; i++ )
  38.         {
  39.             writer.send(" ");
  40.             writer.send(this.whatAmI[i++];
  41.         }
  42.     }
  43.  
  44.     /+
  45.     // The above is analagous to this:
  46.     @property nothrow string toString() const
  47.     {
  48.         return whatAmI[0] ~" "~ whatAmI[1] ~" "~ whatAmI[2] ~" "~ whatAmI[3];
  49.     }
  50.     +/
  51.  
  52.     /+
  53.     // But I'd really like to be able to derive .toString from .stringizer
  54.     // by mixin template:
  55.     mixin toString!(typeof(this));
  56.     +/
  57. }
  58.  
  59. /// A suboptimal-yet-convenient StringVacuum implementation that collects
  60. /// text from a type's `stringize` method and places it all into one
  61. /// GC-allocated string.
  62. class StringizationConcatenator : StringVacuum
  63. {
  64. private:
  65.     import std.array;
  66.     Appender!string contents_;
  67.  
  68. public:
  69.     @property pure const @nogc nothrow
  70.     string contents() { return contents_.data; }
  71.  
  72.     this()
  73.     {
  74.         contents_ = appender!string();
  75.     }
  76.  
  77.     void send(string  plainText) { contents_.put(plainText); }
  78.     void send(wstring plainText) { contents_.put(plainText); }
  79.     void send(dstring plainText) { contents_.put(plainText); }
  80.  
  81.     void send(char  oneChar)     { contents_.put(oneChar); }
  82.     void send(wchar oneChar)     { contents_.put(oneChar); }
  83.     void send(dchar oneChar)     { contents_.put(oneChar); }
  84. }
  85.  
  86. /// This template allows a type that implements the `stringize` method to
  87. /// get a `toString` method for free.
  88. ///
  89. /// After all, `stringize` is just a generalized version of `toString`.
  90. ///
  91. mixin template toString(T)
  92. {
  93.     private import std.traits : FA = FunctionAttribute;
  94.  
  95.     // Generate a .toString method with SOME, but not ALL, of the function attributes
  96.     // that the type's `stringize` method has.
  97.     //
  98.     // For example:
  99.     // If T's `stringize` is nothrow, then this implies that the derived `toString` is nothrow.
  100.     // If T's `stringize` is @nogc, then the derived `toString` is still NOT @nogc,
  101.     //     because StringizationConcatenator GC-allocates.
  102.     //
  103.     // (Also I'm pretty sure this won't compile, albeit I haven't tested it.
  104.     // The below code is intended to express intent, not be a valid implementation.)
  105.     //
  106.     @property
  107.     ...
  108.     mixin(stringizeFunctionAttributes!(
  109.    
  110.         // This is a template that I haven't implemented yet. Does what the name suggests.
  111.         getStringizeMethod!T,
  112.  
  113.         // Tentative list of attributes that get forwarded. Anything not here is not forwarded, ex: @nogc.
  114.         FA.pure_  | FA.nothrow_ | FA.trusted | FA.safe | FA.system |
  115.         FA.const_ | FA.shared_  | FA.live
  116.     ))
  117.     ...
  118.     string toString()
  119.     {
  120.         // Body of our boilerplate toString method.
  121.         scope vacuum = new StringizationConcatentator();
  122.         this.stringize(vacuum);
  123.         return vacuum.result;
  124.     }
  125. }
  126.  
  127. /// Creates a string of function attribute(s)
  128. /// that are found on the given `func`.
  129. /// Only attributes present in the `selectedAttrs`
  130. /// argument will be present in the resulting string;
  131. /// all others will be discarded.
  132. ///
  133. template stringizeFunctionAttributes(alias func, FunctionAttribute selectedAttrs)
  134.     if (func.length == 1 && isCallable!func)
  135. {
  136.     import std.array : join;
  137.     import std.traits : functionAttributes, FunctionAttribute;
  138.  
  139.     alias FA = FunctionAttribute;
  140.  
  141.     FA attrs = functionAttributes!func & selectedAttrs;
  142.  
  143.     enum stringizeFunctionAttributes = [""
  144.         , (attrs & FA.pure_      ? "pure"    : "")
  145.         , (attrs & FA.nothrow_   ? "nothrow" : "")
  146.         , (attrs & FA.ref_       ? "ref"     : "")
  147.         , (attrs & FA.property   ? "@property" : "")
  148.         , (attrs & FA.trusted    ? "@trusted" : "")
  149.         , (attrs & FA.safe       ? "@safe"   : "")
  150.         , (attrs & FA.nogc       ? "@nogc"   : "")
  151.         , (attrs & FA.system     ? "@system" : "")
  152.         , (attrs & FA.const_     ? "const"   : "")
  153.         , (attrs & FA.immutable_ ? "immutable" : "")
  154.         , (attrs & FA.inout_     ? "inout"   : "")
  155.         , (attrs & FA.shared_    ? "shared"  : "")
  156.         , (attrs & FA.return_    ? "return"  : "")
  157.         , (attrs & FA.scope_     ? "scope"   : "")
  158.         , (attrs & FA.live       ? "@live"   : "")
  159.         ].join(" ");
  160. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement