/* Copyright (C) 2006 Christopher E. Miller This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /** Simplified handling of D functions taking a variable number of arguments. Download $(LINK2 http://www.dprogramming.com/variadic1.zip, variadic1.zip) **/ //module std.variadic; module variadic; private import std.stdarg; /// VArgs variadic(TypeInfo[] arguments, va_list argptr) { VArgs result; result.arguments = arguments; result.argptr = argptr; return result; } /// struct VArgs { /// For each argument. int opApply(int delegate(inout VArgs*) dg) { int result = 0; for(iw = 0; iw < arguments.length;) { VArgs* va; va = this; result = dg(va); if(result) break; if (!incremented) { skip(); } incremented = false; } return result; } /// Property: get the _type of the next argument, or null if no more arguments. TypeInfo type() // getter { if(iw >= arguments.length) return null; return arguments[iw]; } /// Skip to the next argument without returning it. /// Returns: true if the argument is present, false otherwise. bool skip() { if(iw >= arguments.length) return false; // bit of magic I don't understand, stolen from stdarg.d argptr += ((arguments[iw].tsize() + int.sizeof - 1) & ~(int.sizeof - 1)); iw++; incremented = true; return true; } /// Get the value of the current argument and advance to the next one. /// Returns: true if the argument is present, false otherwise. bool next(T)(inout T arg) in { assert(typeid(T) == type); } body { if(iw >= arguments.length) return false; arg = va_arg!(T)(argptr); iw++; incremented = true; return true; } /// Get the value of the current argument. /// Does not advance to the next argument. /// Returns: true if the argument is present, false otherwise. bool get(T)(inout T arg) in { assert(typeid(T) == type); } body { if(iw >= arguments.length) return false; arg = *cast(T*)(argptr); return true; } private: TypeInfo[] arguments; va_list argptr; size_t iw; bool incremented = false; } unittest { void foo(...) { int cnt=0; foreach(arg; variadic(_arguments, _argptr)) { printf("%d: ", cnt++); if(arg.type == typeid(char[])) { char[] str; arg.next(str); printf("%.*s", str); if (str == "one more") { arg.next(str); printf(", and it is: \"%.*s\"", str); } else if (str == "skip one") { arg.skip(); printf(" "); } } else if(arg.type == typeid(int)) { int i; arg.get(i); printf("%d", i); arg.get(i); printf(". Let me repeat that: %d!", i); // will be auto incremented } else { printf(""); // will be auto incremented } printf("\n"); } } foo("hello", "world", 42, "one more", "got one more", "skip one", "IF YOU SEE ME THERE'S A BUG", -10.0, "(that was a float)"); } int main(char[][] args) { return 0; }