1 (изменено: m00slim25, 2023-12-03 18:03:29)

Тема: AHK v2: Имитация C-like <typedef enum>

Вобщем вот плоды изысканий.
Тривиальным, как в С, не выглядит... Согласен.


#Requires Autohotkey v2.0

typedef_enum(
  &STD_FIRST,
  &STD_SECOND,
  &STD_THIRD := 0x100,
  &STD_FOURTH,
  &STD_FIFTH := 0x200,
  &STD_SIXTH,
  &STD_SEVENTH
)

printf('{:} {:} {:}', STD_FIRST, STD_SECOND, STD_SEVENTH)

typedef_enum(p*)
{
  e := p.__Enum(2)
  while e(&i, &val)
  {
    if IsSet(%val%)
      t := %val%
    else
      %p[i]% := i = 1 ? t := 0 : t += 1
  }
}

printf(fstr,p*)=>outputdebug(format(fstr,p*))

Хотелось бы узнать мнения.
А ещё лучше предложения.

2

Re: AHK v2: Имитация C-like <typedef enum>

m00slim25, ознакомьтесь, пожалуйста, с Правилами, отредактируйте свой пост. Обратите внимание на точки в конце предложений.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3 (изменено: m00slim25, 2023-12-03 18:02:23)

Re: AHK v2: Имитация C-like <typedef enum>

null.

4

Re: AHK v2: Имитация C-like <typedef enum>

А какой смысл делать это в AHK? Я так понимаю, что в C элементы enum — это неизменяемые значения. В AHK вы такого поведения не сможете добиться.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK v2: Имитация C-like <typedef enum>

teadrinker пишет:

А какой смысл делать это в AHK?

Чтобы не мучаться со значениями, когда таких переменных ну очень много, и разбиты они на множество независимых групп.
Есть AHK, он может проставить все значения автоматически, вот пусть работает.

ЗЫ. Задумал было переделать функцию typedef_enum в одну строку с помощью fat arrow, и что то никак не получается... Всё время какие то ошибки вылазят. Или соображалка уже устала.

6

Re: AHK v2: Имитация C-like <typedef enum>

Если нужно просто присваивать значения переменным по этому принципу и хотите сократить код, можно так:

#Requires Autohotkey v2.0

typedef_enum(
    &STD_FIRST,
    &STD_SECOND,
    &STD_THIRD := 0x100,
    &STD_FOURTH,
    &STD_FIFTH := 0x200,
    &STD_SIXTH,
    &STD_SEVENTH
)

MsgBox Format('{} {} {}', STD_FIRST, STD_SECOND, STD_SEVENTH)

typedef_enum(p*)
{
    for k, v in p {
        %v% ?? %v% := k = 1 ? 1 : %p[k - 1]% + 1
    }
}

Либо однострочник:

typedef_enum(p*) => (e := p.__Enum(2), [((*) => e(&k, &v) && (%v% ?? %v% := k = 1 ? 1 : %p[k - 1]% + 1, 1))*])
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK v2: Имитация C-like <typedef enum>

teadrinker пишет:
%v% ?? %v% := k = 1 ? 1 : %p[k - 1]% + 1

Да, коротенько, интересно.
Только ошибочка вкралась. Оператор enum начинает перечисление с 0, если значение первого параметра не задано.

%v% ?? %v% := k = 1 ? 0 : %p[k - 1]% + 1
teadrinker пишет:

Либо однострочник:

typedef_enum(p*) => (e := p.__Enum(2), [((*) => e(&k, &v) && (%v% ?? %v% := k = 1 ? 1 : %p[k - 1]% + 1, 1))*])

Впервые вижу такую конструкцию.
Вызывается функция с перечислителем, который будет перечислять пока не закончится перечислимое ?
А что за странный вызов ?

[( ... )*]

Что он означает ? И как должен работать ?

8

Re: AHK v2: Имитация C-like <typedef enum>

[( ... )*] можно записать, как Array(( ... )*). В данном случае Array() это функция с переменным количеством параметров. В такую функцию можно передавать как перечислимый объект, так и непосредственно перечислитель. Анонимная функция

(*) => e(&k, &v) && (%v% ?? %v% := k = 1 ? 1 : %p[k - 1]% + 1, 1)

имитирует поведение перечислителя, возвращая 1, когда вызов e(&k, &v) возвращает 1, и 0 в ином случае. Таким образом, эта анонимная функция будет вызываться, пока не вернёт 0.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK v2: Имитация C-like <typedef enum>

teadrinker
Очень интересная техника. Благодарю за разъяснение!

10

Re: AHK v2: Имитация C-like <typedef enum>

Только, вызывая энумераторы подобным образом, нужно иметь в виду, что цикл for k, v in obj выполняется в несколько раз быстрее.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11 (изменено: m00slim25, 2023-12-04 15:03:33)

Re: AHK v2: Имитация C-like <typedef enum>

teadrinker пишет:

Только, вызывая энумераторы подобным образом, нужно иметь в виду, что цикл for k, v in obj выполняется в несколько раз быстрее.

Ну это же очевидно. Машинный код одного оператора, и куча интерпретируемых конструкций.
«Это и ежу понятно...»©

12 (изменено: m00slim25, 2023-12-06 23:02:57)

Re: AHK v2: Имитация C-like <typedef enum>

Ну и поставим, так сказать, жырную точку. И закроем уже тему.
Миллион вызовов функции в цикле Loop: (десять аргументов без значений)

1. 4,8 секунд

typedef_enum(p*)
{
  for i,v in p
    %v%??%v%:=i=1?0:%p[i-1]%+1
}

2. 6,8 секунд

typedef_enum(p*)
{
  e := p.__Enum(2)
  while e(&i,&v)
    %v%??%v%:=i=1?0:%p[i-1]%+1
}

3. 14 секунд

typedef_enum(p*)=>(e:=p.__Enum(2),[((*)=>e(&i,&v)&&(%v%??%v%:=i=1?0:%p[i-1]%+1,true))*])

ПС. Странный эффект от толстой стрелки. Много раз видел такое, обёртывая разнообразные вызовы DllCall в толстую стрелку - время исполнения вызова ощутимо увеличивается, даже если целевая DLL уже загружена в контекст Autohotkey.
Но это уже совсем другая история.

13

Re: AHK v2: Имитация C-like <typedef enum>

Вообще я для реализации объекта, похожего на Enum, использовал бы другой подход:

#Requires AutoHotkey v2

preset := Map(1, -5, 4, 20)
length := 5
MyEnum := Enum(preset, length)

MsgBox 'MyEnum: ' . MyEnum.toString()

MsgBox 'MyEnum[2]: ' . MyEnum[2]

try MyEnum[2] := 100
catch Error as e {
    MsgBox e.Message, 'Error', 16
}

MsgBox 'MyEnum.Length: ' . MyEnum.Length

try MyEnum.Length := 3
catch Error as e {
    MsgBox e.Message, 'Error', 16
}

try MyEnum.Push(42)
catch Error as e {
    MsgBox e.Message, 'Error', 16
}

class Enum extends Array
{
    __New(presetMap, length) {
        this.Length := length
        for k, v in this {
            this[k] := presetMap.Has(k) ? presetMap[k] : k = 1 ? 0 : this[k - 1] + 1
        }
        getItem := Array.Prototype.GetOwnPropDesc('__Item').Get
        this.DefineProp('__Item', {
            get: (s, i) => getItem(s, i),
            set: (*) => this.throwError('Enum element cannot be changed')
        })
        getLength := Array.Prototype.GetOwnPropDesc('Length').Get
        this.DefineProp('Length', {
            get: (s) => getLength(s),
            set: (*) => this.throwError('Enum length cannot be changed')
        })
        for method in ['Delete', 'InsertAt', 'Pop', 'Push', 'RemoveAt'] {
            this.DefineProp(method, {
                call: ((method, *) => this.throwError(method . '() method is not defined')).Bind(method)
            })
        }
    }

    toString() => (
        str := '', e := this.__Enum(2),
        [((*) => e(&k, &v) && (str .= (k = 1 ? '[' : ', ') . v, 1))*],
        str . ']'
    )

    throwError(text) {
        throw Error(text)
    }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK v2: Имитация C-like <typedef enum>

teadrinker
Код конечно интересный. Спасибо. Но такая реализация не подойдёт.

Идея была именно в автоматической инициализации списков переменных. И реализованнго выше алгоритма пока что, на данном этапе, вполне достаточно.

В то же время, в процессе реализации, стало понятно, что полностью имитировать поведение «C-like enum» не удастся. По крайней мере без поддержки на уровне интерпретатора Autohotkey (а это, боюсь, будет та же история, что с Си-шным циклом for(statement, condition, expression) - Lexikos упорно сопротивляется любым просьбам о её реализации вот уже несколько лет).

Поэтому, я считаю, любые имитации, отходящие от начального плана - это «имитации ради имитаций». Что, в общем то, излишне.
Тем не менее ещё раз спасибо за интересный код.

15

Re: AHK v2: Имитация C-like <typedef enum>

А в каком случае вместо переменных нельзя использовать элементы массива?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK v2: Имитация C-like <typedef enum>

В случае, когда лучше сделать всё как можно проще.

17

Re: AHK v2: Имитация C-like <typedef enum>

Я не уговариваю, но разве не проще сразу получить все значения в массиве, чем указывать все переменные по одной?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18 (изменено: m00slim25, 2023-12-08 12:02:45)

Re: AHK v2: Имитация C-like <typedef enum>

В каком то, отдельно взятом случае, возможно - да, было бы удобнее.
Но для общего применения - отнюдь, первоначальный подход удобнее.

ЗЫ. И вот, кстати, я не до конца понял, либо не понял совсем. Если я в своём примере подаю на вход функции рефы на переменные, там же и объявляемые, а на выходе получаю эти переменные уже со значениями, то в Вашем примере ничего, кроме массива значений, я не увидел. Объяснитесь, пожалуйста.

19

Re: AHK v2: Имитация C-like <typedef enum>

Не совсем тоже понял, в чём вопрос. Ну да, получаем сразу массив значений, без предварительного указания переменных. Аналогом переменных STD_FIRST, STD_SECOND ... будет MyArray[1], MyArray[2] ...

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20

Re: AHK v2: Имитация C-like <typedef enum>

Блин, примерно такого ответа я и ожидал...
Ок, «мыло и мачало, начнём ка всё сначало»©
Цель: автоматизировать присваивание значений спискам переменных, с конкретно, и жёстко, заданными именами.
Глобальный список может быть сколь угодно гигантским - десятки, сотни переменных.
Глобальный список разбит на подгруппы, состоящие из единиц, десятков, значительно реже - сотен переменных.
Порядок присваиваемых значений целочисленный инкрементный последовательный. Может начинаться с произвольного числа, либо с нуля, если начальное значение стартовой переменной не задано.
Последовательность может прерываться как в рамках глобального списка, так и в рамках конкретной локальной подгруппы.

Сама задача взята из кропотливого создания врапперов для DLL библиотек, написанных на C/C++. Со всеми вытекающими.
Так как в исходном коде оригиналов повсеместно используется встроенный оператор enum, и возникла идея перенести (сразу оговорюсь - перенести частично!!!) поведение оператора по автоматизированному присвоению значений спискам переменных в сам враппер, силами Autohotkey.
Ничего большего не требовалось.

Надеюсь, что теперь разъяснил более детально.

ЗЫ. Никаких полноценных свойств enum не требуется! Это просто невозможно. Константы не поддерживаются Autohotkey. Присвоение переменной внутри списка значения другой переменной из того же списка, но объявленной ранее - невозможно, throw ValueError будет итогом такой попытки.
Любые попытки «колдовать» над решением этих невозможностей - избыточны. Поэтому смысла не имеют.

21

Re: AHK v2: Имитация C-like <typedef enum>

Понял, что цель — неполноценно сымитировать enum, просто потому, что очень хотелось неполноценно сымитировать enum. Ну, ок.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK v2: Имитация C-like <typedef enum>

Ну, по всему выходит, что да - можно и так сказать.