chadjoan

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

Jul 31st, 2020
2,119
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×