D - static if on variadic arguments not working properly - d

Suppose I have the following variadic function, which job is to concat together a path from pieces (each piece can either be an index of integral type, or a node of string type):
string
makePath(P...)(P path)
{
import std.conv;
import std.format;
string res;
foreach (piece; path) {
pragma(msg, typeof(piece).stringof);
static if (is(piece: size_t))
res = res is null ? piece.to!string : format("%s[%s]", res, piece);
else if (is(piece: string))
res = res is null ? piece : format("%s.%s", res, piece);
else
static assert(0);
}
}
If I later use it like this: string path = makePath("foo", "bar"), somehow the code reaches the static assert(0); and the compilation terminates. This is most curious, but the pragma actually writes string as the type of the first argument despite the fact that a code path for some other type was taken.
Even better, using makePath(12, 13) results in the compiler complaining about both the line for strings (about incompatible types of int and string) and static assert. What is going on here?
I've tried this both on DMD and LDC.

The is keyword is what's at fault here. (It's quite a confusing keyword I find...)
I'd recommend you use the templates in std.traits to test for types, most there are covered: https://dlang.org/phobos/std_traits.html
Here's a working version of your function:
string
makePath(P...)(P path)
{
import std.conv;
import std.format;
import std.traits : isSomeString, isNumeric;
string res;
foreach (piece; path) {
static if (isNumeric!(typeof(piece)))
res = res is null ? piece.to!string : format("%s[%s]", res, piece);
else static if (isSomeString!(typeof(piece))) // Note, you were missing the 'static' on the 'else if' part
res = res is null ? piece : format("%s.%s", res, piece);
else
static assert(0);
}
return res;
}
unittest {
static assert(makePath("foo","bar") == "foo.bar");
static assert(makePath("foo","bar",1) == "foo.bar[1]");
}

Related

How to convert PyObject to UTF-8 string?

I'm trying to pass a string value to a Python function and get a utf-8 string value. The function retrieves Japanese characters and returns characters in another language.
I used ctypes.windll.user32.MessageBoxW in the Python script and made sure there is no problem with the Python function. And I tried a simple function like return 'hello world' to test. I also checked every function with assert. I guess the problem starts with PyBytes_AsString. It always returns DB DB DB DB DB DB DB... (in hex). But I don't know how to fix this.
char* result;
PyObject* module, *func, *arg, *ret, *value;
Py_Initialize();
PyObject* sysPath = PySys_GetObject("path");
PyObject* path = PyUnicode_FromString(".");
PyList_Append(sysPath, path);
module = PyImport_ImportModule("test");
if (module != 0)
{
const wchar_t* w = L"翻訳テスト";
func = PyObject_GetAttrString(module, "translate");
arg = PyTuple_New(1);
value = PyUnicode_FromWideChar(w, wcslen(w));
PyTuple_SetItem(arg, 0, value);
ret = PyObject_CallObject(func, arg);
PyObject* repr = PyObject_Repr(ret);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "strict");
result = PyBytes_AsString(str);
Py_DECREF(repr);
Py_DECREF(str);
Py_DECREF(module);
Py_DECREF(func);
Py_DECREF(arg);
Py_DECREF(ret);
fstream file("text.txt", std::ios::out);
file << result;
file.close();
}
Py_Finalize();
result = PyBytes_AsString(str) returns a pointer to the internal buffer of str, so don't Py_DECREF(str) before you write result to the file.

Get the variable values at runtime using reflection in Dlang

Is it possible to get the class/struct/other variables value during runtime in dlang to get/set its value? If yes how to do that please provide example.
And also is it possible to get the runtime variable value?
Ex:
class S{ int svariable = 5;}
class B { int bvariable = 10;}
void printValue(T, T instanceVariable, string variableName) {
writeln("Value of ", variableName, "=", instanceVariable.variableName);
}
Output:
Value of svariable = 5;
Value of bvariable = 10;
There is a library named witchcraft that allows for runtime reflection. There are examples of how to use it on that page.
I'd first recommend trying a reflection library like #mitch_ mentioned. However, if you want to do without an external library, you can use getMember to get and set fields as well as invoke functions:
struct S {
int i;
int fun(int val) { return val * 2; }
}
unittest {
S s;
__traits(getMember, s, "i") = 5; // set a field
assert(__traits(getMember, s, "i") == 5); // get a field
assert(__traits(getMember, s, "fun")(12) == 24); // call a method
}

How to remove the attributes from a function type?

In the following sample the first test fails because of the function type attributes. The second test overrides the problem but it's too syntactically heavy.
import std.traits;
bool test1(T)()
{
// clean but does not work !
alias Fun = bool function(dchar);
return (is(Unqual!T == Fun));
}
bool test2(T)()
{
// super heavy !
return (isSomeFunction!T && is(ReturnType!T == bool) &&
Parameters!T.length == 1 && is(Parameters!T[0] == dchar)
);
}
void main(string[] args)
{
import std.ascii: isAlpha;
assert(test1!(typeof(&isAlpha)));
assert(test2!(typeof(&isAlpha)));
}
Is there a way to remove the attributes, just like Unqual does to storage classes ?
Check this out: http://dlang.org/phobos/std_traits.html#SetFunctionAttributes
std.traits.SetFunctionAttributes
alias ExternC(T) = SetFunctionAttributes!(T, "C", functionAttributes!T);
auto assumePure(T)(T t)
if (isFunctionPointer!T || isDelegate!T)
{
enum attrs = functionAttributes!T | FunctionAttribute.pure_;
return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}
That example adds the attribute pure but a similar pattern can remove attributes too.

C++ urljoin equivalent

Python has a function urljoin that takes two URLs and concatenates them intelligently. Is there a library that provides a similar function in c++?
urljoin documentation: http://docs.python.org/library/urlparse.html
And python example:
>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html', 'FAQ.html')
'http://www.cwi.nl/%7Eguido/FAQ.html'
I figured it out. I used the library uriparser: http://uriparser.sourceforge.net/ and hastily implemented the function as follows. It does sparse error checking and may leak memory.
std::string urljoin(std::string &base, std::string &relative)
{
UriParserStateA state;
UriUriA uriOne;
UriUriA uriTwo;
state.uri = &uriOne;
if (uriParseUriA(&state, base.c_str()) != URI_SUCCESS)
{
return "";
}
state.uri = &uriTwo;
if (uriParseUriA(&state, relative.c_str()) != URI_SUCCESS)
{
uriFreeUriMembersA(&uriTwo);
return "";
}
UriUriA result;
if (uriAddBaseUriA(&result, &uriTwo, &uriOne) != URI_SUCCESS)
{
uriFreeUriMembersA(&result);
return "";
}
uriFreeUriMembersA(&uriOne);
uriFreeUriMembersA(&uriTwo);
int charsRequired;
uriToStringCharsRequiredA(&result, &charsRequired);
charsRequired++;
char *buf = (char*) malloc(charsRequired * sizeof(char)); if (uriToStringA(buf, &result, charsRequired, NULL) != URI_SUCCESS)
return "";
uriFreeUriMembersA(&result);
std::string ret(buf);
free(buf);
return ret;
}
The Poco::URI class in the POCO C++ Libraries can do that (see the resolve() member function).
Short answer, not really.
You would have to parse the string and replace the tail. This would be fairly easy using, for example, boost::regex.

Lua toString exception for boolean value

I wrote a simple lua function which uses 'C++' function to execute. As my intention of creating a 'C++' function is to use the same across all lua functions to update the 'C++' variables. It works fine for numbers, but when I tried it for boolean values, it give me exception when convert to string.
Here is my code snippet.
C++ code.
#include <lua.hpp>
/* the Lua interpreter */
lua_State *luaState;
std::map<lua_State *, CLuaTest *> luaFbtlookup;
void CLuaTest::CLuaTest() {
// initialize Lua
luaState = luaL_newstate();
lua_register(luaState, "get_value", get_value); // func to get values
lua_register(luaState, "set_value", set_value); // func to set values
// load Lua base libraries
luaL_openlibs(luaState);
luaL_dofile(luaState, "C:\LuaTest.lua");
luaFbtlookup.insert(make_pair(luaState, this));
}
int get_value(lua_State *L);
int set_value(lua_State *L);
extern "C++" int get_value(lua_State *L)
{
string lightName = lua_tostring(L, 1);
FbTLuaLookup::iterator iter = luaFbtlookup.find(L);
if (iter != luaFbtlookup.end()) {
lua_pushstring(L, iter->second->getValueFrom(lightName).c_str());
return 1; // do not return zero
}
return 1;
}
extern "C++" int set_value(lua_State *L)
{
string lightName = lua_tostring(L, 1);
if (NULL == lua_tostring(L, 2))
{
printf("WARNING : Invalid String Argument / Cannot convert arg#2 to string");
}
else {
string value = lua_tostring(L, 2);
FbTLuaLookup::iterator iter = luaFbtlookup.find(L);
if (iter != luaFbtlookup.end()) {
iter->second->setValueTo(lightName, value);
lua_pushnumber(L, true);
return 1; // do not return zero
}
}
return 1;
}
CLuaTest::ExecuteScript(enum Seq) {
switch(Seq) {
case 0:
lua_getglobal(luaState, "AllLightsOff");
break;
case 1:
lua_getglobal(luaState, "RedLightOn");
break;
case 2:
lua_getglobal(luaState, "AmberLightOn");
break;
case 3:
lua_getglobal(luaState, "GreenLightOn");
break;
}
}
My lua script:
function AllLightsOff
set_value("RedLight", 0)
set_value("AmberLight",0)
set_value("GrenLight",0)
end
function RedLightOn
set_value("RedLight", 1)
set_value("AmberLight",0)
set_value("GrenLight",0)
end
function AmberLightOn
set_value("RedLight", 0)
set_value("AmberLight",1)
set_value("GrenLight",0)
end
function GreenLightOn
set_value("RedLight", 0)
set_value("AmberLight",0)
set_value("GrenLight",1)
end
Things work fine with the above code, but when I tried to change the set value to use boolean values like set_value("RedLight", False) I get warning message printing. Should I need to pass False as string?
Lua doesn't have False, so it simply tries to read global _G["False"] which is of course nil.
It has false keyword, however, but it wouldn't work either: lua_tostring is working only for numbers and strings.
We don't see setValueTo code, so it is hard to guess how it works.
If you simply want to pass bool value to it, use lua_toboolean, but be aware that it treats 0 as true (as Lua in general).
If you want to pass "True" or "False" as strings, then yes, you must write set_value("RedLight", "False")
As a side note, consider reading how to implement lua_CFunction protocol. Now, if get_value can't find lightName, it will return the last passed parameter as its result.