Официальный сайт компании Arduino по адресу arduino.cc
Шаблон CList
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Пнд, 27/03/2017 - 23:40
Этот шаблон я использую как динамический список для объектов, кроме примитивных (для них я создаю специализированные классы).
#pragma once typedef struct _NODE { void * Data; struct _NODE * Next; } * PNODE, NODE; template < class T > class CList { private: PNODE _head; PNODE _tail; protected: CList & _self; private: T & GetItem( int index ) { PNODE pNode = _head; while ( index-- ) { if ( pNode == NULL ) { break; } pNode = pNode->Next; } return * reinterpret_cast< T * >( pNode->Data ); } public: int Count; public: CList() : _self( * this ) { _head = NULL; _tail = NULL; Count = 0; } explicit CList( const CList<T> & obj ) { Clear(); AddRange( obj ); } ~CList() { Clear(); } CList<T> & operator=( const CList<T> & copy ) { while ( Count > 0 ) { RemoveAt( 0 ); } for ( int n = 0; n < copy.Count; n++ ) { Add( new T ( copy[n] ) ); } return * this; } // Setter. T & operator[]( int index ) { return GetItem( index ); } // Getter. T & operator[]( int index ) const { return const_cast< CList<T> * >( this )->GetItem( index ); } bool Empty() { return Count == 0; } T * Add( T * item ) { if ( item == NULL ) return NULL; PNODE node = new NODE; if ( node == NULL ) { return NULL; } node->Data = item; node->Next = NULL; if ( Count == 0 ) { _head = node; } else { _tail->Next = node; } _tail = node; Count++; return item; } void AddRange( const CList<T> & source ) { for ( int n = 0; n < source.Count; n++ ) { Add( & source[n] ); } } void RemoveAt( int index ) { if ( index > Count - 1 ) return; PNODE Curr = _head, Prev = NULL; int n = index; if ( Curr != NULL ) { while ( n-- ) { Prev = Curr; Curr = Curr->Next; } if ( index == 0 ) { _head = Curr->Next; } else { Prev->Next = Curr->Next; } delete Curr; Count--; } } void Clear() { while ( Count > 0 ) { RemoveAt( 0 ); } } };
Для любителей C++. Пример использования (взято из моей программы, где я подключаю прерывания динамически по своему алгоритму).
Interrupts.h
Interrupts.cpp
Другой пример. Элемент иерархического меню с использованием CList. Очень удобно делать меню. Только заголовочный файл.
Этот шаблон я использую как динамический список
Молодец!
Я пытался использовать stl для avr, но он тяжеловат.
здесь тебя за это никто не похвалит. Не жди.
Вы не так поняли, хвалить буду я, если поймёте как это работает и сможете использовать. Кто сможет, тому будет большое облегчение при работе с коллекцией объектов неизвестного размера и произвольного типа.
хвалить буду я, если поймёте как это работает и сможете использовать. Кто сможет, тому будет большое облегчение при работе с коллекцией объектов неизвестного размера и произвольного типа.
Понятно.
И помни, что: "Хотя шаблоны предоставляют краткую форму записи участка кода, на самом деле их использование не сокращает исполняемый код, так как для каждого набора параметров компилятор создаёт отдельный экземпляр функции или класса."
Механизм шаблонов для этих огрызков не предназначен. Использовать то, канеш, можно. Но принесет ли это нам радость?
гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно.
Это не так, как уже много лет как показано тут. На easyelectrinics много лет тому назад была серия статей, где проводился анализ ассемблерного года при использовании шаблонов. Так что ... идти и читать статьи от neiver.
Я везде на avr использую его шаблон умных указателей для работы с памятью программ. Очень удобно и код такой же как без них по объёму.
и это,
039
public
:
040
int
Count;
такие вещи как Count, памойму, надо делать функциями, чтобы снаружи они были только для чтения (жалка, что в C++ свойств нетути). Неудобно, канеш, скобки кажный раз писать, зато не срубица в неположенном месте из-за того, что кто-то умный изменил Count напрямую.
И помни, что: "Хотя шаблоны предоставляют краткую форму записи ...
Коллега - википедик? :)
скорее, всёподрядчитатель. C# шаблоны мне нравюца больше.
Я могу показать рабочий код, который достаточно хорошо имитирует свойства в C++, но это сложнее, чем CList, народ не поймёт вообще. Поэтому используется публичное поле. Если использовать функции, то это будут setter и getter. Я не перфикционист, мне достаточно публичного поля.
гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно.
Точней к указателям на что угодно. И про громоздкость компиляции шаблонов, тоже общеизвестно, потому действительно на МК предложеный подход плох. А уж про необходимость иметь " коллекцией объектов неизвестного размера и произвольного типа." - вобще не встречается на МК при правильном проектировании задачи (ну не ориентироватся же на приблудившихся вебдизайнеров желающих хранить произвольные переменные с произвольными именами). Максимум встречается неизвестное кол-во известных датчиков, и соответственно данных под них. А при подробном рассмотрении и количество очень даже ограничено аппаратно.
В общем громоздкое решение неактуальной задачи. А уж чтоб писать меню на таком, надо совсем не думать о ресурсах. И это учитывая что каждый второй ответ на вопросы по меню - сделать в PROGMEM)))
Автору не останавливатся boost на avr еще загадочней и бесполезней.
Кто не страдает стереотипами, тот возьмёт на вооружение, остальные останутся со своими word'ами.
П.С. Где я использую этот шаблон:
- при построении иерархического меню, используя класс, который содержит коллекцию экземпляров самого себя (меню формируется динамически при загрузке);
- при загрузке внешних данных, например, информации о тегах для modbus, которые должны быть расположены в массиве неизвестного заране размера (определяется внешним файлом);
- при создании фреймов запросов для modbus, они формируются на основании тегов и создаются при загрузке один раз;
- при создании окон для графического индикатора;
и т.д.
Очень удобно иметь типизированный шаблон :)
Понятно. Код для оригиналов,неформалов, нетрадициалов и личностей в состоянии расширеного сознания.
Понятно. Код для оригиналов,неформалов, нетрадициалов и личностей в состоянии расширеного сознания.
нужно брать - дайте два
ну вот ТС boost под avr допишет - будет два )))
гораздо честнее создать один List, хранящий список word-ов, которые потом можно приводить к чему угодно.
Покажите пример, я бы хотел взглянуть на эту реализацию и пример использования.
Странная порода эволюционировала с развитием IT. STL и Boost они знают, а односвязній список им "покажи". uni, читайте класику )))
Logik, этот список реализован у меня, раскрой спойлер с исходником. Мне не понятно чем List с word'ами будет отличаться?
У меня void * - этот тот же word в архитекуре avr. Я поэтому и спрашиваю, чем List word'ов отличается от List'а word'ов?
Правка. Может это не ясно из примеров, но CList содержит указатели на экземпляры классов. При добавлении элемента нужно в качестве параметра передавать его адрес. Т.е. вы выделяете память под ваш тип и полученный адрес передаёте списку. Объекты сами в списке не хранятся.
//Мне не понятно чем List с word'ами будет отличаться?
Это хреново. Должен бы понимать, что в односвязном списке есть только одна операция естественно следующая из его структуры. Это GetNext. Используя её легко строится все, например поиск элемента, в один проход. А как будет выглядеть поиск в твоем коде и за сколько проходов? Хреново что ты такого не понимаеш, а на чето претендуеш.
ПС. А уж то, что при умении работать с односвязным списком за один проход делается и поиск множества по различным сложным критериям, возможно с попутным внесением изменений в некоторые элементы, возможно с удалением некоторых элементов или копированием их или выводом нахер и пр. любителям либ не интересно. Им только интересно, чего их либа так тормозит то ;)
//Мне не понятно чем List с word'ами будет отличаться?
Это хреново. Должен бы понимать, что в односвязном списке есть только одна операция естественно следующая из его структуры. Это GetNext. Используя её легко строится все, например поиск элемента, в один проход. А как будет выглядеть поиск в твоем коде и за сколько проходов? Хреново что ты такого не понимаеш, а на чето претендуеш.
Да уж... поиск элемента по индексу реализован в методе GetItem(), где твой GetNext() это вот этот код:
Чудо! Там поиск по номеру а я по элементу хочу. А номер в односвязном, то вобще ни о чем. Удалил элемент - вся нумерация поплыла. Так что индексом его громко не называй, однозначного соответствия между ним и данными нет.
Logik, лучше больше не комментируй... люди о тебе мнение составят... далекое от того, о чём ты сам о себе думаешь. Открой лучше спойлер с кодом и попробуй всё-таки понять как это работает.
Я понял, предметный разговор ты окончил, т.к. осознал дибилизм своего творения. И решил перейти на личности.
Если захочеш вернутся в цивилизацию то оцени порядок сложности поиска элемента в своем творении. Для односвязного списка он известен O(n).
Logik, бесполезно что-то объяснять человеку, который не хочет прочитать код. Для тебя, я вижу, это барьер и ты пытаешься биться о него глупыми замечаниями, вместо того, чтобы получать ответы от самого кода. Там написаны все ответы, а в примерах ещё и дополнительные.
На личности ты переходишь. Я пытаюсь заставить тебя код прочитать, а ты всё глупостями в мой адрес сыплешь. Выше человек сделал правильное замечание по поводу поля Count. Бери с него пример и хватит нести ахинею всякую. Что ни пост, то 2 х 2.
А я говорил, что тебе здеся будут не рады...
Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами, а основная масса, которая здесь тусуется, начинают темы со слов "помогите новичку вынести горшок". Им то что ты написал - настолько дико, что использовать это никто не будет, зато охотно забросают тебя калом по самые нихачу.
Да ладно Вам, Logic, ну написал человек как ему нравится, и молодец. То, что в реализации "списка" нет классических операций car и cdr, зато есть какие-то индексы, меня тоже несколько удивило, а реализация функции Clear() так вообще в восторг привела! Но, видать такие они - нынешние списки :) В любом случае, этот пост гораздо приятнее вопросов "почему функция if не компилируется?".
Понятнно, uni, ниосилил оценить сложность своего творения)) А она квадратична, т.к. внутри цикла по все элементам будет лежать цикл поиска заданого по индексу, который в среднем будет прокручиватся до половины списка, потому n*n/2. Т.е. при наличии 1000 элементов в спмске и 10мксек на обработку элемента в односвязном списке мы найдем элемент не хуже чем за 10мсек. А в приведеном классе за 5сек.
Тема откуда берутся тормознутые проги и програмисты раскрыта полностью. Надеюсь и ответ на "Мне не понятно чем List с word'ами будет отличаться?" тоже понят.
А я говорил, что тебе здеся будут не рады...
Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами, а основная масса, которая здесь тусуется, начинают темы со слов "помогите новичку вынести горшок". Им то что ты написал - настолько дико, что использовать это никто не будет, зато охотно забросают тебя калом по самые нихачу.
Тонкое понимание вопроса, однако))) Да. Согласен.
Гуру себе сами списки пишут, под каждую свою аппаратную задачу - конкретные, не раздувая код шаблонами
Не впервой. А что значит не раздувая код шаблонами? Т.е. если мне нужно 4 таких списка, но каждый с разным типом объекта, то как будет выглядеть нераздутый код? Неужели он будет прям настолько нераздутым? Что аж никто до сих пор не осмелился показать свой вариант. Если это список word'ов, то это совершенно ничем не отличается от варианта с шаблоном, кроме неудобства приведения.
Понятнно, uni, ниосилил оценить сложность своего творения)) А она квадратична, т.к. внутри цикла по все элементам будет лежать цикл поиска заданого по индексу, который в среднем будет прокручиватся до половины списка, потому n*n/2. Т.е. при наличии 1000 элементов в спмске и 10мксек на обработку элемента в односвязном списке мы найдем элемент не хуже чем за 10мсек. А в приведеном классе за 5сек.
Тема откуда берутся тормознутые проги и програмисты раскрыта полностью. Надеюсь и ответ на "Мне не понятно чем List с word'ами будет отличаться?" тоже понят.
Это было бы дельным замечанием, если бы у меня была реализована функция поиска. Поскольку ты спойлер с шаблоном не открывал, то не знаешь, что функции поиска там нет. В шаблоне есть метод получения элемента по индексу.
Если тебе нужен метод поиска, то он делается точно также как GetItem(), только в качестве параметра передаётся специальный указатель на функцию, получающую на входе элемент и возвращающую на выходе true или false. Поскольку он будет реализован также как GetItem(), то и работать он будет как O(n).
У меня нет такого функционала, т.к. он мне не был нужен. Ты решал свои задачи, а я свои. Моей задачей было - не дублировать лишний код при работе с динамическими списками (у меня их много) и получение доступа к конкретному элементу. Даже очистка и удаление сделаны чисто для некоторой завершённости. Пользоваться ими нужно с умом, а лучше не пользоваться.
Если я удалю элемент в списке при помощи RemoveAt(), то связность от этого не нарушится, т.к. в коде предусмотрено "сшивание" соседних узлов списка.
Если расширять шаблон, то я бы сделал варианты запросов из Linq в C#, но это отдельная работа.
Ещё раз. Внутри шаблона все переходы по списку работают непосредственно с указателями, о чём я указывал выше. То, что у меня не реализована функция поиска... ну, извините, я могу показать как её добавить и как использовать. А писать всякие домыслы о несуществующем (воображаемом) коде ... как вообразите - то и получите.
Я понял, Logik, чего ты хочешь. Тебе нужен итератор. Ну, извини, итератора у меня нет. Предполагается, что итерирования не нужно. Шаблон должен предоставлять нужные методы, скрывая перебор, т.е. если тебе нужен поиск, то нужно реализовать его внутри шаблона, скрыв перебор по элементам. Вручную перебирать элементы не нужно.
Если бы я написал функцию поиска, то её использование выглядело бы как-то так:
TItem * pItem = list.Find( [](x) => { return x.Field == 0; } );
Не помню точно как должно выглядеть лямбда выражение. Внутри шаблона при этом реализуется Find() как я указал выше. Мне лично итераторы не нужны.
Я могу добавить ряд таких методов и потом показать пример как с ними работать, а Logik может потом проверить действительно ли с ростом количества элементов у меня будет что-то не так с производительностью и конечно покажет свой вариант.
Не впервой. А что значит не раздувая код шаблонами? Т.е. если мне нужно 4 таких списка, но каждый с разным типом объекта, то как будет выглядеть нераздутый код? Неужели он будет прям настолько нераздутым? Что аж никто до сих пор не осмелился показать свой вариант. Если это список word'ов, то это совершенно ничем не отличается от варианта с шаблоном, кроме неудобства приведения.
т.е, если тебе нужно 4 таких списка, с разным типом объекта, то компилятор создаст 4 разных класса, функции которого будут заточены под конкретный тип объекта, так, насколько я понимаю, работает механизм шаблонов в С++. Разделять код между экземплярами классов не выйдет. Зато такого не случится, сделай ты список хранящий void *. Кастовать конечно придется вручную, ну дак мы и не в сказку попали же. Это Си, матьиво.
С другой стороны, я могу ошибаться. Многоуважаемые гуру поправят меня.
Хм, это можно проверить. Я могу показать листинги компиляции для какого-нибудь предложенного примера. У меня есть возможность удобно их получать.
Тут есть ещё одна тонкость, о которой я не упомянул. Этот класс используется не только на avr, я его использую ещё в многопоточной среде и на самом деле часть кода я удалил из примера, который ограничивал работу со списком при работе из разных потоков.
Организация шаблона тоже сделана так, чтобы не происходило блокировки при работе. Может из-за этого код выглядит не оптимизированным для однопоточной среды. Надо убрать лишнее.
Я понял, Logik, чего ты хочешь. Тебе нужен итератор. Ну, извини, итератора у меня нет.
Мне нужно, если уж деле дошло до односвязного списка (что повторяю, для МК не типичная задача) и поиска в нем, такие строчки.
а может в другой точке
или
а может
Это быстро просто и эффективно. Да, конечно, можна завернуть в шаблоны это while ( pNode ) {...; pNode=pNode->Next;}, сделать итераторы, лямды, хулямды и т.д. Только не факт что вобще чего сэкономится, цикл примитивен. Он прост даже для новичка, если он не будет тратить время на твой код под спойлером, а прочитает за то же время статью по односвязным спискам.
Вот и видим два пути для новичка:
1. Изучить конкретную либу, собственно её интерфейс и примеры применения, заюзать, затем посреди проекта столкнутся с её неэффективностью. Прибежать на форум с криками "памагите", "где найти другую либу" и пр. При этом оставатся в полной уверености что главное в програмировании - найти нужную либку. Вот и получится продвинутый владеющий десятками либ, тормознутых и глюкавых в разной степени, и абсолютно не понимающий суть процесса изнутри. Ему вечно не хватает, то ОЗу, то скорости проца, то новой либы.
2. Изучить теорию по односвязным спискам и писать эти 3-5 строк по мере надобности в том виде как нужно по месту получать максимально эффективное решение задачи. При этом комбинируя и перебирая варианты обработки данных для оптимизации учитывая специфику. С таким уже хоть есть о чем поговорить по сути.
TItem * pItem = list.Find( [](x) => { return x.Field == 0; } );
TItem * pItem = list.Find( [](TItem * x) ->bool { return x.Field == 0; } );
Но старые ИДЕ не поддерживают.
Я могу добавить ряд таких методов и потом показать пример как с ними работать, а Logik может потом проверить действительно ли с ростом количества элементов у меня будет что-то не так с производительностью и конечно покажет свой вариант.
ПС. Я не противник либ вобще, есть к примеру CriptoLib, GZIP и др. действительно необходимые вещи. Если кто решится им конкурента написать, зовите, почитаю. А писать тормознутую, глюкавую хрень и пускать её в народ не надо. Не хороше так с народом поступать.