Показаны сообщения с ярлыком Vala. Показать все сообщения
Показаны сообщения с ярлыком Vala. Показать все сообщения
В позапрошлом посте рассказывалось о создании экземпляров объектов GObject по имени класса, где, кроме всего прочего, было сказано:
Лично у меня данный пример как есть в Windows не заработал (собирал компилятором mingw). Не удавалось найти указатель на функцию cow_get_type. Опытным путем выяснилось, что работает такой механизм при соблюдении двух условий:
Получается: либо типы всех потенциально загружаемых из файла объектов должны быть заранее зарегистрированы, т.е. все (обязательно все) и явно (в каком-то виде) типы должны быть прописаны в коде разработчиком, либо же нужен неизящный и непортабельный механизм вроде поиска в таблице символов исполняемого файла для имени каждого подгружаемого из файла класса соответствующего метода foo_bar_get_type... и вызова этого метода.Все почти так и есть, но в коде GtkBuilder случайно был найден довольно изящный и портабельный механизм поиска foo_bar_get_type. Идея простая: нужно создать объект GModule не для динамически загружаемого модуля, а для самой программы. Для чего в метод g_module_open(const gchar *file_name, GModuleFlags flags) вместо имени файла нужно передать NULL:
file_name — the name of the file containing the module, or NULL to obtain a GModule representing the main program itself.Пример на Vala на основе идей из GtkBuilder (механизм получения типа по имени класса иллюстрирует функция type_from_name_lazy):
public abstract class Animal : Object
{
public abstract string to_string();
}
public class Cow : Animal
{
public override string to_string()
{
return "I'm a cow!";
}
}
public class Dog : Animal
{
public override string to_string()
{
return "I'm a dog!";
}
}
int main()
{
Animal a;
Type type;
a = new Dog(); //< Явно создаем Dog, имя типа зарегистрировано в системе типов.
print("1) %s\n", a.to_string());
if((type = Type.from_name("Dog")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("2) %s\n", a.to_string());
}
else
print("2) Failed to get type!\n");
if((type = Type.from_name("Cow")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("3) %s\n", a.to_string());
}
else
{
print("3) Failed to get type! Trying type_from_name_lazy...\n");
if((type = type_from_name_lazy("Cow")) != Type.INVALID)
{
a = Object.new(type) as Animal;
print("3) %s\n", a.to_string());
}
else
print("3) Failed to get type!\n");
}
return 0;
}
[CCode (has_target = false)]
delegate Type TypeGetFunc();
Type type_from_name_lazy(string name)
{
void *func = null;
if(Module.open(null, 0).symbol(ascii_camel_to_snake(name) + "_get_type", out func))
return ((TypeGetFunc)func)();
else
return Type.INVALID;
}
string ascii_camel_to_snake(string input)
{
var sb = new StringBuilder();
for(int i = 0; input[i] != '\0'; i++)
{
if(
( input[i].isupper() && i > 0 && !input[i - 1].isupper() ) ||
( (i > 2 && input[i].isupper()) && input[i - 1].isupper() && input[i - 2].isupper() )
)
sb.append_c('_');
sb.append_c(input[i].tolower());
}
return sb.str;
}
Вывод программы: 1) I'm a dog!И немного про Windows
2) I'm a dog!
3) Failed to get type! Trying type_from_name_lazy...
3) I'm a cow!
Лично у меня данный пример как есть в Windows не заработал (собирал компилятором mingw). Не удавалось найти указатель на функцию cow_get_type. Опытным путем выяснилось, что работает такой механизм при соблюдении двух условий:
- Объект должен быть реализован в отдельной dll;
- До попытки поиска указателя должна быть вызвана хотя бы одна функция из этой dll.
В предыдущем посте «Клонирование GObject» я рассказывал про идею некоего обобщенного кода, не зависимого от конкретной задачи,
который бы сохранял объекты Gobject в файлы (типы объектов и значения
свойств) и потом воссоздавал последовательность объектов по этим файлам. Предполагалось сохранять в текстовый файл имена классов и порядок объектов, а также имена свойств объектов и их значения.
Идея красивая, но здесь мы сталкиваемся с одним ограничением системы типов GObject (ограничением вполне естественным, т.к. написан GObjecct на Си и вся поддержка ООП реализована на уровне библиотеки): чтобы создать экземпляр класса по имени класса нужно, чтобы этот класс уже был зарегистрирован в системе типов GObject. Т.е. для типа FooBar должен быть заранее вызван метод foo_bar_get_type непосредственно или опосредованно (например, через метод создания вроде foo_bar_new).
Получается: либо типы всех потенциально загружаемых из файла объектов должны быть заранее зарегистрированы, т.е. все (обязательно все) и явно (в каком-то виде) типы должны быть прописаны в коде разработчиком, либо же нужен неизящный и непортабельный механизм вроде поиска в таблице символов исполняемого файла для имени каждого подгружаемого из файла класса соответствующего метода foo_bar_get_type (см. тему на stack overflow) и вызова этого метода.
UPDATE: Найден довольно изящный и портабельный способ поиска метода foo_bar_get_type, см. Создание объектов GObject по имени типа. Часть 2.
Пример на Vala ниже иллюстрирует описанную проблему. Мы можем создать объект типа Dog по имени, т.к. выше уже создан объект типа Dog и класс зарегистрирован в системе типов. Создание объекта типа Cow же завершается неудачей (см. вывод программы после исходного кода).
Идея красивая, но здесь мы сталкиваемся с одним ограничением системы типов GObject (ограничением вполне естественным, т.к. написан GObjecct на Си и вся поддержка ООП реализована на уровне библиотеки): чтобы создать экземпляр класса по имени класса нужно, чтобы этот класс уже был зарегистрирован в системе типов GObject. Т.е. для типа FooBar должен быть заранее вызван метод foo_bar_get_type непосредственно или опосредованно (например, через метод создания вроде foo_bar_new).
Получается: либо типы всех потенциально загружаемых из файла объектов должны быть заранее зарегистрированы, т.е. все (обязательно все) и явно (в каком-то виде) типы должны быть прописаны в коде разработчиком, либо же нужен неизящный и непортабельный механизм вроде поиска в таблице символов исполняемого файла для имени каждого подгружаемого из файла класса соответствующего метода foo_bar_get_type (см. тему на stack overflow) и вызова этого метода.
UPDATE: Найден довольно изящный и портабельный способ поиска метода foo_bar_get_type, см. Создание объектов GObject по имени типа. Часть 2.
Пример на Vala ниже иллюстрирует описанную проблему. Мы можем создать объект типа Dog по имени, т.к. выше уже создан объект типа Dog и класс зарегистрирован в системе типов. Создание объекта типа Cow же завершается неудачей (см. вывод программы после исходного кода).
public abstract class Animal : Object
{
public abstract string to_string();
}
public class Cow : Animal
{
public override string to_string()
{
return "I'm a cow!";
}
}
public class Dog : Animal
{
public override string to_string()
{
return "I'm a dog!";
}
}
int main()
{
Animal a;
Type type;
a = new Dog(); //< Явно создаем Dog, здесь класс и регистрируется в системе типов.
print("1) %s\n", a.to_string());
if((type = Type.from_name("Dog")) != 0)
{
a = Object.new(type) as Animal;
print("2) %s\n", a.to_string());
}
else
print("2) Failed to get type!\n");
if((type = Type.from_name("Cow")) != 0)
{
a = Object.new(type) as Animal;
print("3) %s\n", a.to_string());
}
else
print("3) Failed to get type!\n");
return 0;
}
Вывод программы: 1) I'm a dog!
2) I'm a dog!
3) Failed to get type!
Код основан на примере "Rotated button" из gtk-demo. Собирается под Gtk-2. Местами код неидеален (например виджет RotatedBin.scale создается вручную в main), но, думаю, вполне может быть полезен.
Скрин:
Код:
https://docs.google.com/file/d/0B40UHa6ea9QkdUFTVnRqNnFaTDg/edit
Скрин:
Код:
https://docs.google.com/file/d/0B40UHa6ea9QkdUFTVnRqNnFaTDg/edit
Ключевые слова: example, Gtk, off-screen window, Vala
Потребовалось использовать в программе на Vala некоторые функции небезызвестной библиотеки для вычисления быстрого преобразования Фурье fftw3. Для чего был написан простенький vapi-файл. В силу своего, прямо скажем, мизерного пока еще опыта использования Vala, не рекомендую брать данный vapi за эталон, тем не менее выкладываю его на случай, если кому-то он окажется полезен. В vapi прописаны лишь некоторые функции, типы и константы и лишь для работы с float-значениями, однако, думаю, при необходимости не составит никакого труда файл необходимым образом дополнить по аналогии. fftw_complex было принято решение не использовать, не заворачивать в класс, а по-простому работать напрямую с float-массивами (поэтому осторожней с выделением-освобождением памяти).
Сам vapi-файл:
Пример использования:
В заключение хочу порекомендовать отличное how-to по написанию vapi к не-GObject-библиотекам.
Сам vapi-файл:
[CCode (cprefix = "fftwf_", cheader_filename = "fftw3.h")] namespace Fftwf { [CCode(cprefix = "FFTW_")] enum Sign { FORWARD = -1, BACKWARD = 1 } [CCode(cprefix = "FFTW_")] enum Flag { MEASURE = (0U), DESTROY_INPUT = (1U << 0), UNALIGNED = (1U << 1), CONSERVE_MEMORY = (1U << 2), EXHAUSTIVE = (1U << 3), PRESERVE_INPUT = (1U << 4), PATIENT = (1U << 5), ESTIMATE = (1U << 6) } [CCode(cname = "fftwf_plan")] public struct Plan : int { } // fake int void destroy_plan(Plan p); void execute(Plan p); void free(float *p); float* malloc(size_t n); Plan plan_dft_1d(int n, float* in_ptr, float* out_ptr, Sign sign, Flag flags); }
Пример использования:
{
float input[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
float *data;
float *fft_result;
float *ifft_result;
Fftwf.Plan plan_forward, plan_backward;
int i;
data = Fftwf.malloc( 2 * sizeof(float) * input.length );
fft_result = Fftwf.malloc( 2 * sizeof(float) * input.length );
ifft_result = Fftwf.malloc( 2 * sizeof(float) * input.length );
plan_forward = Fftwf.plan_dft_1d( input.length, (void*)data, (void*)fft_result, Fftwf.Sign.FORWARD, Fftwf.Flag.ESTIMATE );
plan_backward = Fftwf.plan_dft_1d( input.length, (void*)fft_result, (void*)ifft_result, Fftwf.Sign.BACKWARD, Fftwf.Flag.ESTIMATE );
/* populate input data */
for(i = 0 ; i < input.length ; i++)
{
data[2 * i + 0] = input[i];
data[2 * i + 1] = 0.0f;
}
/* print initial data */
for( i = 0 ; i < input.length ; i++ )
{
print("data[%d] = { %2.2f, %2.2f }\n",
i, data[2 * i + 0], data[2 * i + 1] );
}
Fftwf.execute( plan_forward );
/* print fft result */
for(i = 0 ; i < input.length ; i++)
{
print("fft_result[%d] = { %2.2f, %2.2f }\n",
i, fft_result[2 * i + 0], fft_result[2 * i + 1] );
}
Fftwf.execute( plan_backward );
/* print ifft result */
for( i = 0 ; i < input.length ; i++ )
{
print("ifft_result[%d] = { %2.2f, %2.2f }\n",
i, ifft_result[2 * i + 0] / input.length, ifft_result[2 * i + 1] / input.length );
}
/* free memory */
Fftwf.destroy_plan( plan_forward );
Fftwf.destroy_plan( plan_backward );
Fftwf.free(data);
Fftwf.free(fft_result);
Fftwf.free(ifft_result);
}
В заключение хочу порекомендовать отличное how-to по написанию vapi к не-GObject-библиотекам.
"Хозяйке на заметку": прочитать данные (переменные, целые, с плавающей точкой и т.п.) из бинарного файла на Vala можно и нужно с помощью GVariant, например так:
{
uint8[] buf = new uint8[sizeof(uint32) + sizeof(uint32) +
sizeof(double) + sizeof(double)];
{
var data_stream = new DataInputStream(file.read());
data_stream.read(buf);
}
Variant variant = Variant.new_from_data<uint8>(
new VariantType("(uudd)"), buf, true);
uint32 int1 = variant.get_child_value(0).get_uint32();
uint32 int2 = variant.get_child_value(1).get_uint32();
double double1 = variant.get_child_value(2).get_double();
double double2 = variant.get_child_value(3).get_double();
stdout.printf("int 1 = %u\n", int1);
stdout.printf("int 2 = %u\n", int2);
stdout.printf("double 1 = %f\n", double1);
stdout.printf("double 2 = %f\n", double2);
}
Подписаться на:
Сообщения (Atom)
![[Image]](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglZx1zAOvuAotO85VPgPbF8nLu2RwCZXqkZz3VRwGE7TFJVGFHBbS3U9L09AZTRxUFLX6nCWslVt6GxQP6rs26bUlUwaQ3UsSAkXAEiYBSY5DvLvDEj_In0eNrPpwjnGJY2ASx5bBp-eA/s320/rotated_widget.png)