🚀 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 11:07
stała mapa enum -> wartość
#291851
Author: heby
Date: Sun, 10 Mar 2024 11:07
49 lines
1385 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ść
#291852
Author: Jacek Marcin Jaw
Date: Mon, 11 Mar 2024 01:03
10 lines
459 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ść
#291853
Author: heby
Date: Mon, 11 Mar 2024 16:34
17 lines
568 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ść
#291854
Author: JDX
Date: Mon, 11 Mar 2024 17:18
30 lines
1386 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ść
#291855
Author: heby
Date: Mon, 11 Mar 2024 17:36
37 lines
1764 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: =?ISO-8859-2?Q?sta³a?= mapa enum -> =?ISO-8859-2?Q?warto¶æ?
#291856
Author: arnold@hootervil
Date: Tue, 12 Mar 2024 02:37
15 lines
575 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: =?ISO-8859-2?Q?sta³a?= mapa enum -> =?ISO-8859-2?Q?warto¶æ?
#291857
Author: arnold@hootervil
Date: Tue, 12 Mar 2024 02:43
24 lines
1104 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ść
#291858
Author: heby
Date: Tue, 12 Mar 2024 07:23
8 lines
498 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ść
#291859
Author: JDX
Date: Tue, 12 Mar 2024 07:56
12 lines
777 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ść
#291860
Author: heby
Date: Tue, 12 Mar 2024 08:23
9 lines
784 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ść
#291861
Author: JDX
Date: Wed, 13 Mar 2024 01:19
75 lines
2518 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ść
#291862
Author: heby
Date: Wed, 13 Mar 2024 09:16
7 lines
238 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ść
#291863
Author: heby
Date: Wed, 13 Mar 2024 09:21
32 lines
767 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ść
#291871
Author: Jacek Marcin Jaw
Date: Thu, 21 Mar 2024 16:20
30 lines
943 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ść
#291873
Author: heby
Date: Thu, 21 Mar 2024 16:44
26 lines
1016 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