Thread overview
strange with alias this and import
Jan 31, 2020
aquaratixc
Jan 31, 2020
aquaratixc
Jan 31, 2020
aquaratixc
January 31, 2020
I have two files.
First file:
```
module ppmformats;

private
{
	template addProperty(T, string propertyName)
	{
		import std.string : format, toLower;
	
		const char[] addProperty = format(
			`
			private %2$s %1$s;
	
			void set%3$s(%2$s %1$s)
			{
				this.%1$s = %1$s;
			}
	
			%2$s get%3$s()
			{
				return %1$s;
			}
			`,
			"_" ~ propertyName.toLower,
			T.stringof,
			propertyName
			);
	}

	auto EnumValue(E)(E e)
		if(is(E == enum))
	{
		import std.traits : OriginalType;
		OriginalType!E tmp = e;
		return tmp;
	}

}

class RGBColor
{
	mixin(addProperty!(int, "R"));
	mixin(addProperty!(int, "G"));
	mixin(addProperty!(int, "B"));

	this(int R = 0, int G = 0, int B = 0)
	{
		this._r = R;
		this._g = G;
		this._b = B;
	}

	const float luminance709()
	{
	   return (_r  * 0.2126f + _g  * 0.7152f + _b  * 0.0722f);
	}
	
	const float luminance601()
	{
	   return (_r * 0.3f + _g * 0.59f + _b * 0.11f);
	}

	alias luminance = luminance709;

	override string toString()
	{
		import std.string : format;
		
		return format("RGBColor(%d, %d, %d, I = %f)", _r, _g, _b, this.luminance);
	}

	RGBColor opBinary(string op, T)(T rhs)
	{
		import std.algorithm : clamp;
		import std.string : format;

		return mixin(
			format(`new RGBColor(
				clamp(cast(int) (_r  %1$s rhs), 0, 255),
				clamp(cast(int) (_g  %1$s rhs), 0, 255),
				clamp(cast(int) (_b  %1$s rhs), 0, 255)
				)
			`,
			op
			)
		);
	}

	RGBColor opBinary(string op)(RGBColor rhs)
	{
		import std.algorithm : clamp;
		import std.string : format;

		return mixin(
			format(`new RGBColor(
				clamp(cast(int) (_r  %1$s rhs.getR), 0, 255),
				clamp(cast(int) (_g  %1$s rhs.getG), 0, 255),
				clamp(cast(int) (_b  %1$s rhs.getB), 0, 255)
				)
			`,
			op
			)
		);
	}
}

class AnyMapImage
{
	mixin(addProperty!(int, "Width"));
	mixin(addProperty!(int, "Height"));
	
	private
	{
		RGBColor[] _image;

		import std.algorithm : clamp;

		auto actualIndex(size_t i)
		{
			auto S = _width * _height;
		
			return clamp(i, 0, S);
		}

		auto actualIndex(size_t i, size_t j)
		{
			auto W = cast(size_t) clamp(i, 0, _width - 1);
			auto H = cast(size_t) clamp(j, 0, _height - 1);
			auto S = _width * _height;
		
			return clamp(W + H * _width, 0, S);
		}
	}

	this(int width, int height, RGBColor color = new RGBColor(0, 0, 0))
	{
		this._width = width;
		this._height = height;

		foreach (x; 0.._width)
		{
			foreach (y; 0.._height)
			{
				_image ~= color;
			}	
		}
	}

	RGBColor opIndexAssign(RGBColor color, size_t x, size_t y)
	{
		_image[actualIndex(x, y)] = color;
		return color;
	}

	RGBColor opIndexAssign(RGBColor color, size_t x)
	{
		_image[actualIndex(x)] = color;
		return color;
	}

	RGBColor opIndex(size_t x, size_t y)
	{
		return _image[actualIndex(x, y)];
	}

	RGBColor opIndex(size_t x)
	{
		return _image[actualIndex(x)];
	}

	override string toString()
	{
		string accumulator = "[";

		foreach (x; 0.._width)
		{
			string tmp = "[";
			foreach (y; 0.._height)
			{
				tmp ~= _image[actualIndex(x, y)].toString ~ ", ";				
			}
			tmp = tmp[0..$-2] ~ "], ";
			accumulator ~= tmp;
		}
		return accumulator[0..$-2] ~ "]";
	}

	alias width = getWidth;
	alias height = getHeight;
}


enum AnyMapFormat : string
{
	PBM_TEXT 	= 	"P1",
	PBM_BINARY 	=  	"P4",
	PGM_TEXT 	= 	"P2",
	PGM_BINARY	=	"P5",
	PPM_TEXT	=	"P3",
	PPM_BINARY	= 	"P6",
}

abstract class ImageFile
{
	protected
	{
		AnyMapImage _image;
		AnyMapFormat _header;
	}

	abstract void load(string filename);
	abstract void save(string filename);	

}

class P6Image : ImageFile
{
	
	this(int width, int height, RGBColor color = new RGBColor(0, 0, 0))
	{
		_image = new AnyMapImage(width, height, color);
		_header = AnyMapFormat.PPM_BINARY;	
	}

	override void load(string filename)
	{
		import std.conv;
		import std.stdio;
		import std.string;

		File file;

		with (file)
		{
			open(filename, "r");

			if (readln.strip == EnumValue(_header))
			{
				auto imageSize = readln.split;
				auto width = imageSize[0].parse!int;
				auto height = imageSize[1].parse!int;

				_image = new AnyMapImage(width, height);
				auto buffer = new ubyte[width * 3];

				readln;

				for (uint i = 0; i < height; i++)
				{
					file.rawRead!ubyte(buffer);
				
					for (uint j = 0; j < width; j++)
					{
							_image[j, i] = new RGBColor(
										buffer[j * 3],
										buffer[j * 3 + 1],
										buffer[j * 3 + 2]
									);
					}
				}
				
			}
		}
	}

	override void save(string filename)
	{
		import std.conv;
		import std.stdio;
		import std.string;
		
		File file;
				
		with (file)
		{
			enum MAXIMAL_LUMINANCE = 255;
			open(filename, "w");
			writeln(EnumValue(_header));
			writeln(_image.getWidth, " ", _image.getHeight);
			writeln(MAXIMAL_LUMINANCE);
				
			foreach (i; 0.._image.getHeight)
			{
				foreach (j; 0.._image.getWidth)
				{
					auto currentColor = _image[j, i];
					file.write(
						 cast(char) currentColor.getR,
						 cast(char) currentColor.getG,
						 cast(char) currentColor.getB,
								);
				}
			}				
	    }		
	}

	alias _image this;
}

auto medianFilter(P6Image source, int M = 3, int N = 3)
{
	auto imageWidth = source.getWidth;
	auto imageHeight = source.getHeight;
	auto edgeM = M / 2;
	auto edgeN = N / 2;
	auto simg = new P6Image(imageWidth, imageHeight);
	
	for (int i = edgeM; i < imageWidth - edgeM; i++)
	{
		for (int j = edgeN; j < imageHeight - edgeN; j++)
		{
			RGBColor[] window;

			for (int w = 0; w < M; w++)
			{
				for (int h = 0; h < N; h++)
				{
					window ~= source[i + w - edgeM, j + h - edgeN];
				}
			}
			
			import std.algorithm : sort;
			import std.range : array;
			
			auto sortedWindow = (sort!"a.luminance < b.luminance"(window)).array;
			
			simg[i, j] = sortedWindow[(M + N) / 2];
		}
	}
	return simg;
}

//void main()
//{
//	import std.stdio;
//	import std.algorithm : clamp;
//
//	auto img = new P6Image(0, 0);
//	img.load(`Lenna.ppm`);
//	(img[0, 0] * 0.5).writeln;
//	
//	foreach (x; 0..img.width)
//	{
//		foreach (y; 0..img.height)
//		{
//			auto c = img[x, y];
//			img[x, y] = c * new RGBColor(150, 0, 0);
//		}
//	}
//	img.save(`Lenna2.ppm`);
//	img.load(`noise.ppm`);
//	medianFilter(img, 5, 5).save(`antinoise.ppm`);
//}
```

and second:
```
import ppmformats;

void main()
{
    import std.stdio;
    import std.algorithm : clamp;

    auto img = new P6Image(0, 0);
    img.load(`Lenna.ppm`);
    (img[0, 0] * 0.5).writeln;

    foreach (x; 0..img.width)
    {
        foreach (y; 0..img.height)
        {
            auto c = img[x, y];
            img[x, y] = c * new RGBColor(150, 0, 0);
        }
    }
    img.save(`Lenna2.ppm`);
    img.load(`noise.ppm`);
    medianFilter(img, 5, 5).save(`antinoise.ppm`);
}
```

By compilation I have this message:

```
e.d(10): Error: no [] operator overload for type ppmformats.P6Image
e.d(12): Error: no property width for type ppmformats.P6Image
Failed: ["/usr/bin/dmd", "-v", "-o-", "e.d", "-I."]

```

How to fix this ?

January 31, 2020
On 1/31/20 3:55 PM, aquaratixc wrote:

> How to fix this ?
> 

_image is protected, so you can only use the alias-this inside the type itself, or its derivatives.

If you want to expose access, but not allow rebinding, create a public accessor:

final AnyMapImage image() { return _image; }
alias image this;

Now, your other module can see the symbol.

-Steve
January 31, 2020
On Friday, 31 January 2020 at 21:16:07 UTC, Steven Schveighoffer wrote:
> On 1/31/20 3:55 PM, aquaratixc wrote:
>
>> How to fix this ?
>> 
>
> _image is protected, so you can only use the alias-this inside the type itself, or its derivatives.
>
> If you want to expose access, but not allow rebinding, create a public accessor:
>
> final AnyMapImage image() { return _image; }
> alias image this;
>
> Now, your other module can see the symbol.
>
> -Steve

Thanks
January 31, 2020
On Friday, 31 January 2020 at 21:16:07 UTC, Steven Schveighoffer wrote:
> On 1/31/20 3:55 PM, aquaratixc wrote:
>
>> How to fix this ?
>> 
>
> _image is protected, so you can only use the alias-this inside the type itself, or its derivatives.
>
> If you want to expose access, but not allow rebinding, create a public accessor:
>
> final AnyMapImage image() { return _image; }
> alias image this;
>
> Now, your other module can see the symbol.
>
> -Steve

I have another question (offtopic): from first file I want to create one-file _source_ library for dub (I need it for instant access for features of this lib on my smartphone), but I don't understand how point to dub (in sdl format) what this file is source library.
Know you how to do this?