Я хотел бы создать векторную структуру в D, который работает как это:
vec u, v;
vec w = [2,6,8];
v.x = 9; // Sets x
v[1] = w.y; // Sets y
u = v; // Should copy data
Позже я также хотел бы добавить материал как u = v * u
и т.д. Но вышеупомянутое сделает на данный момент.
Это - то, как далеко я приехал:
struct vec3f
{
float[3] data;
alias data this;
@property
{
float x(float f) { return data[0] = f; }
float y(float f) { return data[1] = f; }
float z(float f) { return data[2] = f; }
float x() { return data[0]; }
float y() { return data[1]; }
float z() { return data[2]; }
}
void opAssign(float[3] v)
{
data[0] = v[0];
data[1] = v[1];
data[2] = v[2];
}
}
Теперь это в значительной степени заставляет его работать как, я хотел, но я чувствую себя очень не уверенным в том, если это "правильно". Должен opAssign (), возможно, возвращают некоторое значение?
Я также задаюсь вопросом, действительно ли это с такой скоростью, как это может быть? Я, попытались добавить alias data[0] x;
и т.д., но это не работает. Какие-либо идеи? Или это, "как это сделано"? Возможно, компилятор достаточно умен, чтобы выяснить, что функции propery являются более или менее псевдонимами?
В целом это выглядит вполне разумно. Для целей цепочки назначений opAssign, возможно, должен возвращать v. Однако на практике это часто упускается из виду и может вызвать снижение производительности (я не знаю). В отличие от D1, вы можете возвращать статические массивы из функций в D2.
Что касается производительности, лучше всего думать об этом на уровне сборки. Предполагая, что встраивание включено, x ()
почти наверняка будет встроенным. Статические массивы хранятся непосредственно в структуре без дополнительного уровня косвенного обращения. Инструкция return data [0];
заставит компилятор сгенерировать код для чтения со смещения от начала структуры. Это смещение будет известно во время компиляции. Поэтому, скорее всего, вызов x ()
сгенерирует точно такие же инструкции сборки, как если бы x
на самом деле была общедоступной переменной-членом.
Еще одна возможность - использовать анонимное объединение и структуру:
struct vec3f
{
union {
float[3] vec;
struct {
float x;
float y;
float z;
}
}
alias vec this; // For assignment of a float[3].
}
Обратите внимание, хотя этот псевдоним this
сейчас довольно глючит, и вам, вероятно, пока не стоит его использовать, если только вы готовы отправить несколько отчетов об ошибках.
Вы можете использовать opDispatch для переключения произвольной глубины. Я также рекомендую создать шаблон для вашей векторной структуры по размеру и типу. Вот моя версия для сравнения: tools.vector (D1, поэтому swizzling немного сложнее).
Вы можете использовать операцию с массивом, чтобы скопировать весь массив за один раз в opAssign:
data[] = v[];
@property
{
float x(float f) { return data[0] = f; }
float y(float f) { return data[1] = f; }
float z(float f) { return data[2] = f; }
float x() { return data[0]; }
float y() { return data[1]; }
float z() { return data[2]; }
}
Зачем свойства?
Я бы предложил убрать эти строки и сделать x, y и z публичными полями. Это также улучшит производительность в неинлайновом режиме. Вы можете использовать union, чтобы иметь массив data[3] в любом случае.