6 days ago

I'm currently using these new implementations of core.lifetime.move


	import core.stdc.string : memcpy;

	/++ Variant of `core.lifetime.move(source)` that uses `__rvalue`.

		If `T` is a struct with a destructor or postblit defined, source is
        reset to its `.init` value after it is moved into target, otherwise it
        is left unchanged.

        See https://github.com/dlang/dmd/pull/20946/files.
	 +/
	 /+TODO:ref+/ T move(T)(return scope ref T source) @trusted /+TODO:__rvalue+/ {
		static if (__traits(isStaticArray, T)) {
			typeof(return) destination = void;
			foreach (const i, ref e; source) // TODO: use single call to `moveEmplaceAll`
				// TODO: Replace with: new (destination[i]) typeof(T.init[i])(__rvalue(e)); // placement new
				moveEmplace(e, destination[i]);
			return destination;
		} else {
			typeof(return) destination = __rvalue(source); // runs move constructors if present
			static if (is(T == struct) && (__traits(hasMember, T, "__xdtor") || __traits(hasMember, T, "__fieldPostblit"))) {
				static immutable init = T.init;
				memcpy(&source, &init, T.sizeof);
			}
			return destination;
		}
	}

	/++ Variant of `core.lifetime.move(source, destination)` that uses `__rvalue`.

		If `T` is a struct with a destructor or postblit defined, source is
        reset to its `.init` value after it is moved into target, otherwise it
        is left unchanged.
	 +/
	void move(T)(ref T source, ref T destination) @trusted {
		static if (__traits(isStaticArray, T)) {
			foreach (const i, ref e; source) // TODO: use single call to `moveAll`
				move(e, destination[i]);
		} else {
			destination = __rvalue(source); // runs move constructors if present
			static if (is(T == struct) && (__traits(hasMember, T, "__xdtor") || __traits(hasMember, T, "__fieldPostblit"))) {
				static immutable init = T.init;
				memcpy(&source, &init, T.sizeof);
			}
		}

	}

	/++ Variant of `core.lifetime.moveEmplace(source, destination)` that uses `__rvalue`.

		If `T` is a struct with a destructor or postblit defined, source is
        reset to its `.init` value after it is moved into target, otherwise it
        is left unchanged.
	 +/
	void moveEmplace(T)(ref T source, ref T destination) @system {
		static if (__traits(isStaticArray, T)) {
			foreach (const i, ref e; source) // TODO: use single call to `moveEmplaceAll`
				moveEmplace(e, destination[i]);
		} else {
			memcpy(&destination, &source, T.sizeof); // TODO: Use `__rvalue` here?
			static if (is(T == struct)) {
				static if ((__traits(hasMember, T, "__xdtor") || __traits(hasMember, T, "__fieldPostblit"))) {
					static immutable init = T.init;
					memcpy(&source, &init, T.sizeof);
				}
			}
		}
	}

.

How can these be improved?

I'm asking because uncommenting the usages of placement new in the implementations triggers segmentation faults that I fail to understand the source of.

I also haven't found a way to qualify any of the overloads with __rvalue.