🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.c
15 messages
15 total messages Started by heby Sun, 10 Mar 2024 10:07
stała mapa enum -> wartość
#310515
Author: heby
Date: Sun, 10 Mar 2024 10:07
50 lines
2392 bytes
Cześć.

Jest:

enum class Foo : unsigned char {
[...]
};

Gdzieś indziej mam w programi potrzebę następujacą:

Bar getBarFromFoo( Foo _foo )
{
	[...]
}

Mapowanie jest stałe przez cały czas trwania programu.
Enumeratorów jest dużo (prawie 200). Nie wszystkie 256 wartości są 
wypełnione, dziury są nieregularne.

Nie istnieje jakiś sensowny pattern mapowania, jest praktycznie randomowy.

Chciałbym, najprościej, dostać jakąs taką translację:

Bar bar[256];

i czytać to przez bar[(int)_foo].

Tablica bar powinna być we flash (system embedded) więc jakiekolwiek 
mapy "normalne" odpadają, chodzi o wygenerowanie jej na stałe i sięganie 
jedną instrukcją asm.

Mam dwie opcje:
1) napisać mały programik w C++ który zaczya definicję enumeratora Foo, 
zaczyta tablicę translacji Foo->Bar, wypełni struktury a następnie 
zrzuci te 256 bajtów do pliku
2) To samo w pythone, ale wtedy nie będzie łatow odczytać oryginalny 
enumerator (jego wartości).

Potem te 256 bajtowe pliki można zapakować do .o i zlinkować do programu 
jako "dane we flash".

Jest jakies kretywne rozwiązanie inicjacji tej tablicy bez wygibasów 
przez zewnatrzne programy?

Czyli coś jak:

Bar bar[256] = magic::assign_map< Foo:One, Bar(30) >[...].

Aby wykonało się to wszystko na compile time i podczas linkowania była 
już tylko tablica 256 bajtów, zainicjowana.
Re: stała mapa enum -> wartość
#310516
Author: Jacek Marcin Jaworski
Date: Mon, 11 Mar 2024 00:03
11 lines
1518 bytes
W dniu 10.03.2024 o 11:07, heby pisze:
> 
> Jest jakies kretywne rozwiązanie inicjacji tej tablicy bez wygibasów 
> przez zewnatrzne programy?

Konwertery i generatory to standard i właściwe rozw. (przede wszystkim 
ekonomiczne i skuteczne, bo robią co trzeba). Normalnie koduje je się 
jako pierwsze przy rozp. nowego proj.

Piszesz chaotycznie. Jest wrażenie, że ma to się kompilować na systemie 
wbudowanym. Mimo, że wydaje się to nonsensowne.
Re: stała mapa enum -> wartość
#310517
Author: heby
Date: Mon, 11 Mar 2024 15:34
18 lines
1650 bytes
On 11/03/2024 01:03, Jacek Marcin Jaworski wrote:
> Konwertery i generatory to standard i właściwe rozw. (przede wszystkim 
> ekonomiczne i skuteczne, bo robią co trzeba). Normalnie koduje je się 
> jako pierwsze przy rozp. nowego proj.

Tutaj muszę wygenerować jednorazowo 256 bajtów. Pisanie do tego 
"generatora" jest mało sensowne.

> Jest wrażenie, że ma to się kompilować na systemie 
> wbudowanym.

To pewnie wrażenie wynikajace z tego zdania:

"Tablica bar powinna być we flash (system embedded)"

> Mimo, że wydaje się to nonsensowne.

Mi nie.
Re: stała mapa enum -> wartość
#310518
Author: JDX
Date: Mon, 11 Mar 2024 16:18
31 lines
2532 bytes
On 11.03.2024 16:34, heby wrote:
> On 11/03/2024 01:03, Jacek Marcin Jaworski wrote:
>> Konwertery i generatory to standard i właściwe rozw. (przede wszystkim 
>> ekonomiczne i skuteczne, bo robią co trzeba). Normalnie koduje je się 
>> jako pierwsze przy rozp. nowego proj.
> 
> Tutaj muszę wygenerować jednorazowo 256 bajtów. Pisanie do tego 
> "generatora" jest mało sensowne.
Nie bardzo rozumiem w czym jest problem. Tzn. rozumiem, że funkcję
Bar = f(Foo) masz już gdzieś jakoś zdefiniowaną/opisaną (np. na kartce 
papieru czy wewnątrz funkcji getBarFromFoo()). W czym więc problem, aby 
jednorazowo przepisać („wygenerować”) tę funkcję do pliku .cpp 
zawierającego np. coś w stylu:
const Bar foo2bar[256] = { /* opcjonalnie „static const” */
	Bar(7),
	Bar(2),
	(Bar)0, /* 0 -> wartość „niezdefiniowana */
	Bar(1),
	...
};
Zakładam, że bar jest typem typu POD.

Taka tablica powinna wylądować w sekcji .rodata (mówimy oczywiście o 
jedynie słusznym gcc), która na platformie klasy „mały embedded” powinna 
z kolei wylądować we Flashu.

Ewentualnie, aby nie było żadnych wątpliwości, należy pobawić się z
__attribute__ ((section ("nazwa sekcji"))) 
(https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html) i 
domyślnie używanym skryptem linkera (być może wystarczy go przeczytać, 
niekoniecznie modyfikować).
Re: stała mapa enum -> wartość
#310519
Author: heby
Date: Mon, 11 Mar 2024 16:36
38 lines
2928 bytes
On 11/03/2024 17:18, JDX wrote:
>> Tutaj muszę wygenerować jednorazowo 256 bajtów. Pisanie do tego 
>> "generatora" jest mało sensowne.
> Nie bardzo rozumiem w czym jest problem. Tzn. rozumiem, że funkcję
> Bar = f(Foo) masz już gdzieś jakoś zdefiniowaną/opisaną (np. na kartce 
> papieru czy wewnątrz funkcji getBarFromFoo()). W czym więc problem, aby 
> jednorazowo przepisać („wygenerować”) tę funkcję do pliku .cpp 
> zawierającego np. coś w stylu:
> const Bar foo2bar[256] = { /* opcjonalnie „static const” */
>      Bar(7),
>      Bar(2),
>      (Bar)0, /* 0 -> wartość „niezdefiniowana */
>      Bar(1),
>      ...
> };

Widzisz, zakładasz, że potrafisz "zgadnąć" kolejnośc enumeratorów Foo. 
Ona nie jest stabilna. Jak ktoś doda/usunie enumerator Foo, to ta 
tablica tego automatycznie nie dostosuje. To generuje ciężkie do 
odnalezienia błędy.

Ja wiem, że Foo:X1 mapuje się na Bar(3,4). Ale Foo::X2 na Bar(15,2). 
Który element tablicy to Foo::X1 to wie tylko kompilator. Nigdzie nawet 
nie podaję wartości liczbowych dla tego enumeratora, wyliczają się "same".

Aby taka deklaracja jak powyżej działała, musiałbym pozbyć się Foo::X1 i 
pozostałych oraz liczyć na szczęscie, że prawidłowo uda mi się utrzymać 
niejawnie numery tablicy vs odpowienie Bar wpisując na pałę po kolei Bar.

Tymczasem ja wiem tylko, że Foo::X1->Bar(3,4) i chciałbym, aby to 
"Bar(3,4)" wylądowało automatycznie na właściwej pozycji tablicy bez 
względu na manipulacje przy enumeratorze Foo i jego wartości liczbowe w 
danym momencie.

> Taka tablica powinna wylądować w sekcji .rodata

Z tym nie ma problemu, tak zrobię, jak się nie trafi rozsądne wyjście na 
etapie kompilacji.
Re: stała mapa enum -> wartość
#310520
Author: Arnold Ziffel
Date: Tue, 12 Mar 2024 02:37
16 lines
1846 bytes
heby <heby@poczta.onet.pl> wrote:

> Ona nie jest stabilna. Jak ktoś doda/usunie enumerator Foo, to ta 
> tablica tego automatycznie nie dostosuje. To generuje ciężkie do 
> odnalezienia błędy.

Czasem nie do uniknięcia (nie mówię, że konkretnie tutaj tak jest). Wtedy 
po prostu zostawiam komentarz w stylu: uwaga, zmieniając to-i-to zmień też 
to-i-to.

-- 
Panie doktorze, każdej nocy śnią mi się nagie dziewczęta, jak wbiegają
i wybiegają z pokoju.
- I chce pan, żeby ten sen się nie pojawiał?
- Nie, tylko chciałem spytać, co zrobić, żeby one tak nie trzaskały
drzwiami.
Re: stała mapa enum -> wartość
#310521
Author: Arnold Ziffel
Date: Tue, 12 Mar 2024 02:43
25 lines
2394 bytes
heby <heby@poczta.onet.pl> wrote:

> Ja wiem, że Foo:X1 mapuje się na Bar(3,4). Ale Foo::X2 na Bar(15,2). 
> Który element tablicy to Foo::X1 to wie tylko kompilator. Nigdzie nawet 
> nie podaję wartości liczbowych dla tego enumeratora, wyliczają się "same".

Chyba pozostaje napisanie skryptu uruchamianego przed kompilacją. Niech 
wygeneruje jeden plik źródłowy z funkcją mapującą. Dodaj ten plik do 
wykluczeń w systemie kontroli wersji (albo wrzucaj do innego katalogu, 
który jest już wykluczony), żeby się przypadkiem kiedyś nie wcommitował.

> Tymczasem ja wiem tylko, że Foo::X1->Bar(3,4) i chciałbym, aby to 
> "Bar(3,4)" wylądowało automatycznie na właściwej pozycji tablicy bez 
> względu na manipulacje przy enumeratorze Foo i jego wartości liczbowe w 
> danym momencie.

Czy ta wiedza (jak foo mapuje się na bar) jest potrzebna w programie, czy 
tylko w funkcji, która ma być wygenerowana wspomnianym generatorem?

-- 
Sanitariusze wiozą karetką pacjenta.
- Dokąd jedziemy? - pyta pacjent.
- Do kostnicy - odpowiada sanitariusz.
- Ale ja jeszcze nie umarłem.
- A my jeszcze nie dojechaliśmy.
Re: stała mapa enum -> wartość
#310522
Author: heby
Date: Tue, 12 Mar 2024 06:23
9 lines
1700 bytes
On 12/03/2024 03:43, Arnold Ziffel wrote:
>> Tymczasem ja wiem tylko, że Foo::X1->Bar(3,4) i chciałbym, aby to
>> "Bar(3,4)" wylądowało automatycznie na właściwej pozycji tablicy bez
>> względu na manipulacje przy enumeratorze Foo i jego wartości liczbowe w
>> danym momencie.
> Czy ta wiedza (jak foo mapuje się na bar) jest potrzebna w programie, czy
> tylko w funkcji, która ma być wygenerowana wspomnianym generatorem?

Z grubsza istnieje tylko jeden punkt, Bar getBarFromFoo( Foo );
Re: stała mapa enum -> wartość
#310523
Author: JDX
Date: Tue, 12 Mar 2024 06:56
13 lines
1972 bytes
On 11.03.2024 17:36, heby wrote:
[...]
> Widzisz, zakładasz, że potrafisz "zgadnąć" kolejnośc enumeratorów Foo. 
> Ona nie jest stabilna. Jak ktoś doda/usunie enumerator Foo, to ta 
> tablica tego automatycznie nie dostosuje. To generuje ciężkie do 
> odnalezienia błędy.
Tak, o tym nie pomyślałem. W każdym razie temat mnie zainteresował, 
trochę poszukałem i znalazłem np. taką odpowiedź: 
https://stackoverflow.com/questions/33374241/compile-time-lookup-table-for-enum. 
Zwłaszcza jedno zdanie zwróciło moją uwagę (o czym w zasadzie 
wiedziałem, ale jakoś nie przyszło mi to do głowy): „In C++14, your 
switch function could be constexpr, thanks to relaxed constexpr 
restrictions” – ja bym właśnie z constexpr spróbował się pobawić.
Re: stała mapa enum -> wartość
#310524
Author: heby
Date: Tue, 12 Mar 2024 07:23
10 lines
2044 bytes
On 12/03/2024 07:56, JDX wrote:
> https://stackoverflow.com/questions/33374241/compile-time-lookup-table-for-enum. Zwłaszcza jedno zdanie zwróciło moją uwagę (o czym w zasadzie wiedziałem, ale jakoś nie przyszło mi to do głowy): „In C++14, your switch function could be constexpr, thanks to relaxed constexpr restrictions” – ja bym właśnie z constexpr spróbował się pobawić.

Nie spradzałem tego konkretnego rozwiązania jeszcze, zerknę.

Jednak z konwersją switch()->tablica mam złe doświadczenia - być może 
implementacja gcc na tą arch jakoś specjalnie nie lubi się z tablicami i 
zarówno w AVR jak i ARM dostawałem setkę ifów w asm. Lub też zalezy od 
zwracanego typu - u mnie jest to struct z polami bitowymi, choć 
mieszczący się w bajcie.
Re: stała mapa enum -> wartość
#310525
Author: JDX
Date: Wed, 13 Mar 2024 00:19
76 lines
3841 bytes
On 12.03.2024 08:23, heby wrote:
> On 12/03/2024 07:56, JDX wrote:
>> https://stackoverflow.com/questions/33374241/compile-time-lookup-table-for-enum. Zwłaszcza jedno zdanie zwróciło moją uwagę (o czym w zasadzie wiedziałem, ale jakoś nie przyszło mi to do głowy): „In C++14, your switch function could be constexpr, thanks to relaxed constexpr restrictions” – ja bym właśnie z constexpr spróbował się pobawić.
> 
> Nie spradzałem tego konkretnego rozwiązania jeszcze, zerknę.
A ja z ciekawości właśnie sprawdziłem i wygląda na to, że działa. A w 
bonusie jest zerowe zużycie pamięci (nie trzeba tablicy).

-----------------------------------------------------------------
// Kompilacja: g++ -std=c++20 -O3 -Wall -S testenum.cpp

#include <cstdint>
#include <type_traits>

enum class Foo : uint8_t { D, U, P, A };

struct Bar {
	uint8_t   a;
	uint32_t  b;
	constexpr Bar(uint8_t _a, uint32_t _b) : a(_a), b(_b) {}
};

template<Foo> struct Foo2Bar;

// "Tablica" mapujaca Foo -> Bar
template<> struct Foo2Bar<Foo::D> : std::integral_constant<Bar, 
Bar(7,3)> { };
template<> struct Foo2Bar<Foo::U> : std::integral_constant<Bar, 
Bar(0,0)> { };
template<> struct Foo2Bar<Foo::P> : std::integral_constant<Bar, 
Bar(2,3)> { };
template<> struct Foo2Bar<Foo::A> : std::integral_constant<Bar, 
Bar(1,5)> { };

int footest()
{
	// oczekiwana wartosc zwracana: 21
	static_assert(
		Foo2Bar<Foo::D>::value.a + Foo2Bar<Foo::D>::value.b +
		Foo2Bar<Foo::U>::value.a + Foo2Bar<Foo::U>::value.b +
		Foo2Bar<Foo::P>::value.a + Foo2Bar<Foo::P>::value.b +
		Foo2Bar<Foo::A>::value.a + Foo2Bar<Foo::A>::value.b == 21, "");

	return 	Foo2Bar<Foo::D>::value.a + Foo2Bar<Foo::D>::value.b +
			Foo2Bar<Foo::U>::value.a + Foo2Bar<Foo::U>::value.b +
			Foo2Bar<Foo::P>::value.a + Foo2Bar<Foo::P>::value.b +
			Foo2Bar<Foo::A>::value.a + Foo2Bar<Foo::A>::value.b;
}

const Bar& bartest()
{
	return Foo2Bar<Foo::D>::value;
}
-----------------------------------------------------------------

Dla typów prostych nie potrzeba -std=c++20. W każdym razie np. dla ARM-a 
footest() wygląda tak:
	.global	_Z7footestv
	.syntax unified
	.arm
	.type	_Z7footestv, %function
_Z7footestv:
	.fnstart
.LFB14:
	@ Function supports interworking.
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	mov	r0, #21
	bx	lr
	.cantunwind
	.fnend
	.size	_Z7footestv, .-_Z7footestv

Przy optymalizacji -O0 ładnie widać jak pracowicie są dodawane 
poszczególne stałe.
Re: stała mapa enum -> wartość
#310526
Author: heby
Date: Wed, 13 Mar 2024 08:16
8 lines
1458 bytes
On 13/03/2024 01:19, JDX wrote:
> const Bar& bartest()
> {
>      return Foo2Bar<Foo::D>::value;
> }

Teraz zamień powyższe Foo:D na zmienną. Gdyby to była stała, zamiast 
kombinować, użyłbym boost::mpl::map. Ale jest zmienna.
Re: stała mapa enum -> wartość
#310527
Author: heby
Date: Wed, 13 Mar 2024 08:21
33 lines
1767 bytes
On 10/03/2024 11:07, heby wrote:
> Jest jakies kretywne rozwiązanie inicjacji tej tablicy bez wygibasów 
> przez zewnatrzne programy?

Znalazłem głupie i źle działajace "rozwiązanie", ale może warto 
wiedziec, że jest i takie:

enum class Foo {
	  X
	, Y
	[...]
}

class Bar {
	[...]
}

const Bar tablica[256] = {
	  [Foo:X] = Bar(0,1)
	, [Foo:Y] = Bar(3,4)
	[...]
}

Zalety:
1) Niemożliwe zrobienie błednego mapowania

Wady:
1) To zachowuje się jak inicjacja pól klasy - jest runtime, a nie we flash.
2) Nie można zmieniać kolejności enumeratorów
3) Nie można robić dziur (za wyjatkiem końca wyliczenia)
4) enumerator Foo nie może mieć dziur (X=1, Y=3 nie przejdzie)

Czyli nie to, co chcę, ale przyznam, że składni nie znałem. Bodaj z C99.
Re: stała mapa enum -> wartość
#310528
Author: Jacek Marcin Jaworski
Date: Thu, 21 Mar 2024 15:20
31 lines
2016 bytes
W dniu 10.03.2024 o 11:07, heby pisze:
> Cześć.
> 
> Jest:
> 
> enum class Foo : unsigned char {
> [...]
> };
> 
> Gdzieś indziej mam w programi potrzebę następujacą:
> 
> Bar getBarFromFoo( Foo _foo )
> {
>      [...]
> }

Tak sobie pomyślałem, że można to rozw. podobnie jak z plikami zasobów 
qrc z Qt:
1. Należy zakodować prog. konsoli generujący plik binarny z tablicą 256 
bajtów  generowanych f. getBarFromFoo;
2. Należy zakodować drugi prog. konwertujący ten plik do kodu źródłowego 
w j. C. Po prostu będzie tworzył tablice:
unsigned char [] tablica = { 0xYY, 0xYY, 0xYY, 0xYY, 0xYY, 0xYY, ...};
3. Należy tylko włączyć ten plik do proj.
4. Skompilować całość.

Mi się wydaje to proste i eleganckie. Jest też niezależne od kompilatora.

Przy okazji: Ja mogę w tym pomóc za jakąś sensowną kwotę. Jestem w 
stanie też napisać testy automatyczne do tych programików, bo to dobry 
zwyczaj.
Re: stała mapa enum -> wartość
#310529
Author: heby
Date: Thu, 21 Mar 2024 15:44
27 lines
2107 bytes
On 21/03/2024 16:20, Jacek Marcin Jaworski wrote:
> 1. Należy zakodować prog. konsoli generujący plik binarny z tablicą 256 
> bajtów  generowanych f. getBarFromFoo;

To opcja typu generator.

Z jej "zakodowaniem" w konsoli problem jest taki, że nie jest on 
synchroniczny ze zmianami w pliku enumeratorów.

Należało by zrobić parser tych plików, nawet jakiś prymitywny, a to już 
duża komplikacja.

Albo napisać ten generator w cpp, ale to komplikuje znowu budowanie, bo 
muszę mieć wtedy dwa kompilatory, natywny i cross (to oprogramowanie 
embedded).

Jest jeszcze opcja typu skryptowy c, jak "Ch", ale to już grube 
przegięcie IMHO, to są już języki ezotryczne i coś czuje że i tak nie 
poradzą sobie z nowszą składnią enuma.

> Przy okazji: Ja mogę w tym pomóc za jakąś sensowną kwotę.

Spokojnie, to jest trywialne zagadnienie, ja tylko akademicko pytam jak 
to zrobić elegancko.

Obecnie mam generator w cpp i jak nie będzie jakiegoś super rozwiązania, 
to tak zostanie.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads