LINUX.ORG.RU

Оптимизации в Common Lisp

 , , , , оптимизации


1

7

Пропиарю свой доклад вобщем-то, в том числе тут, потому что почему нет.

https://www.youtube.com/watch?v=5T-XONZCptc&t=16157s

Парни на Fprog/Tbilisi позвали рассказать, ну я вобщем-то рассказал.

Лисп можно докрутить до оптимизаций круче C++ на самом деле.

★★★
Ответ на: комментарий от MOPKOBKA

C++ list не заглядывал

Это gnu реализация такая, у m$ там всё благообразнее и читабельнее.

// list standard header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef _LIST_
#define _LIST_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <xmemory>

#if _HAS_CXX17
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
template <class _Mylist, class _Base = _Iterator_base0>
class _List_unchecked_const_iterator : public _Base {
public:
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::const_pointer;
    using reference       = const value_type&;

    _List_unchecked_const_iterator() noexcept : _Ptr() {}

    _List_unchecked_const_iterator(_Nodeptr _Pnode, const _Mylist* _Plist) noexcept : _Ptr(_Pnode) {
        this->_Adopt(_Plist);
    }

    _NODISCARD reference operator*() const noexcept {
        return _Ptr->_Myval;
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_unchecked_const_iterator& operator++() noexcept {
        _Ptr = _Ptr->_Next;
        return *this;
    }

    _List_unchecked_const_iterator operator++(int) noexcept {
        _List_unchecked_const_iterator _Tmp = *this;
        _Ptr                                = _Ptr->_Next;
        return _Tmp;
    }

    _List_unchecked_const_iterator& operator--() noexcept {
        _Ptr = _Ptr->_Prev;
        return *this;
    }

    _List_unchecked_const_iterator operator--(int) noexcept {
        _List_unchecked_const_iterator _Tmp = *this;
        _Ptr                                = _Ptr->_Prev;
        return _Tmp;
    }

    _NODISCARD bool operator==(const _List_unchecked_const_iterator& _Right) const noexcept {
        return _Ptr == _Right._Ptr;
    }

#if !_HAS_CXX20
    _NODISCARD bool operator!=(const _List_unchecked_const_iterator& _Right) const noexcept {
        return !(*this == _Right);
    }
#endif // !_HAS_CXX20

    _Nodeptr _Ptr; // pointer to node
};

template <class _Mylist>
class _List_unchecked_iterator : public _List_unchecked_const_iterator<_Mylist> {
public:
    using _Mybase           = _List_unchecked_const_iterator<_Mylist>;
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::pointer;
    using reference       = value_type&;

    using _Mybase::_Mybase;

    _NODISCARD reference operator*() const noexcept {
        return const_cast<reference>(_Mybase::operator*());
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_unchecked_iterator& operator++() noexcept {
        _Mybase::operator++();
        return *this;
    }

    _List_unchecked_iterator operator++(int) noexcept {
        _List_unchecked_iterator _Tmp = *this;
        _Mybase::operator++();
        return _Tmp;
    }

    _List_unchecked_iterator& operator--() noexcept {
        _Mybase::operator--();
        return *this;
    }

    _List_unchecked_iterator operator--(int) noexcept {
        _List_unchecked_iterator _Tmp = *this;
        _Mybase::operator--();
        return _Tmp;
    }
};

template <class _Mylist>
class _List_const_iterator : public _List_unchecked_const_iterator<_Mylist, _Iterator_base> {
public:
    using _Mybase           = _List_unchecked_const_iterator<_Mylist, _Iterator_base>;
    using iterator_category = bidirectional_iterator_tag;

    using _Nodeptr        = typename _Mylist::_Nodeptr;
    using value_type      = typename _Mylist::value_type;
    using difference_type = typename _Mylist::difference_type;
    using pointer         = typename _Mylist::const_pointer;
    using reference       = const value_type&;

    using _Mybase::_Mybase;

    _NODISCARD reference operator*() const noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        const auto _Mycont = static_cast<const _Mylist*>(this->_Getcont());
        _STL_ASSERT(_Mycont, "cannot dereference value-initialized list iterator");
        _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot dereference end list iterator");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        return this->_Ptr->_Myval;
    }

    _NODISCARD pointer operator->() const noexcept {
        return pointer_traits<pointer>::pointer_to(**this);
    }

    _List_const_iterator& operator++() noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
        const auto _Mycont = static_cast<const _Mylist*>(this->_Getcont());
        _STL_ASSERT(_Mycont, "cannot increment value-initialized list iterator");
        _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot increment end list iterator");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        this->_Ptr = this->_Ptr->_Next;
        return *this;
    }

    _List_const_iterator operator++(int) noexcept {
        _List_const_iterator _Tmp = *this;
        ++*this;
        return _Tmp;
    }

 //...
};

Ygor ★★★★★
()
Ответ на: комментарий от gaylord

Не, погоди. Вот у тебя два дерева: в одном string, в другом int. Что мешает мне вызвать функцию, которая получает int, на дерево, в котором string?

Несовместимый тип.

struct rbtree_c { ... };
void rbtree_c_set(
  struct rbtree_c *rb,
  const void *element,
  int element_size
);

template <typename T>
class rbtree<T> {
private:
  rbtree_c rb;
public:
  void set(const T* item) { rbtree_c_set(&rb, item, sizeof(T)); }
};

rbtree<int> rbtree_int;
rbtree_int.set("hello"); // error

Если ты шаблонизировал struct RBTree, зачем страдание с char *?

Это обвязка для вызовов, а не для структуры и ее основных методов. Пример выше. Про плюсы этого подхода я написал еще более выше.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от gaylord

Так я и так знаю ответ: тебе не нравятся шаблоны, ты знаешь только сишный препроцессор -> ты пользуешься только сишным процепроцессором.

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

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

Это обвязка для вызовов, а не для структуры и ее основных методов. Пример выше. Про плюсы этого подхода я написал выше.

Так по сути ты уже получил все накладные расходы на парсинг шаблонов, что мог получить. Почему бы не сделать последний шаг T element?

gaylord
()
Ответ на: комментарий от alysnix

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

То, что я знаю, как это работает, не значит, что оно мне нравится. Удивительно, что такие вещи приходится объяснять.

gaylord
()
Ответ на: комментарий от gaylord

Это должно быстрее компилироваться, так как компилятору нужно воссоздать только шаблонные вызовы, а не структуры и методы.

Во вторых, как я писал выше, 1) компилятором код не будет дублироваться на каждый тип, 2) можно будет хранить элементы произвольного размера.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от alysnix

вы вообще странный. читаете хидеры фрибсд и топите за лисп

Я ещё ем баранину и пью кофе. Одеваю штаны и сушу волосы. Как эти вещи вообще друг с другом связаны в твоей голове?

P.S. И да, там был OpenBSD.

gaylord
()
Ответ на: комментарий от gaylord

Или ты про то, что в одной структуре можно хранить элементы разных типов?

Да, разные типы. Ну или один тип разного размера если у него тоже есть flexiable member array. Если зашаблонить тип в структуру, то как потом выделять ноды с разным типом? Вроде никак.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

на знаю чем вы там занимаетесь… но если у гейлорда(вот жеж кликухи на лоре) отнимут любимую погремушку - шаблоны, а классы таки оставят, то надо писать базовый класс rgtree_element но без поля данных. реализовать всю кухню, через горсть виртуальных функций, а потом для конкретнотного типа хранения просто наследоваться от rgtree_element, ставить там поле конкретного типа храннения, и реализовывать вирт функции.

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

alysnix ★★★
()
Ответ на: комментарий от gaylord

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

alysnix ★★★
()
Ответ на: комментарий от MOPKOBKA

Вроде никак.

А может ещё так?

public class MultiArray {

    public static void main(String[] args) {
        var time = System.currentTimeMillis();
        String str = "test";
        int i = 0;
        var lst = new ArrayList<>();
        lst.add(str);
        lst.add(i);
        lst.add(time);
        for(var x: lst) System.out.println(x instanceof Object);
    }
}
Ygor ★★★★★
()
Ответ на: комментарий от alysnix

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

О боги. Ладно, слава богу твоего кода мы никогда не увидим.

gaylord
()
Ответ на: комментарий от MOPKOBKA

Это ничего не значащая даже не мелочь. Выше просил по делу. Любой преобразователь синтаксиса тебе за пару секунд как хочешь представит. Та конвенция наименований нам не случайно и скриптами генерится

slew
()
Ответ на: комментарий от gaylord

Сколько работы, которую за программиста может сделать одно волшебное слово template

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

хочу огорчить, но волшебное слово всю работу за программиста не сделает

Ну как же. Оно сделало всю ту работу, что ты собрался программировать руками. Серьезно, вот одним словом – раз, и готово. Автоматизация!

gaylord
()
Ответ на: комментарий от alysnix

тебе что в лиспе не нравится?

Мне все в нем нравится. Это первый ЯП на котором писать начинал. Вот только заикнись кому сейчас на работе про него, то или тупо вообще ничего не поймут, а те кто поймут, побегут дурку вызывать.

slew
()
Ответ на: комментарий от MOPKOBKA

А какие свойства от Lisp тут нужны?

В лиспе удобно написать совершенно однозначную функцию которая из списка входов постоянно делает список выходов. В простейшем случае входы-выходы тупо с логическими уровнями. В более сложном - наборы всякой накристальной периферии типа UART/PWM/ADC/DAC. Ну типа такое как бы очень навороченное FPGA в котором можно ещё и свои блоки делать. Работать оно может и не будет очень быстро, но однозначность привлекает, а скорость не всегда требуется.

Блоки как в GNU Radio это больше на какой-нибудь verilog похоже. Или если фантазия развита, то на любой SDK типа libopencm. Собираешь что тебе надо из кусочков, но клей приходится варить самому.

Stanson ★★★★★
()
Ответ на: комментарий от Stanson

Ничего не понятно, но очень интересно…

В лиспе удобно написать совершенно однозначную функцию которая из списка входов постоянно делает список выходов

а на си эту «совершенно однозначную функцию» сделать нельзя что-ли?

alysnix ★★★
()
Ответ на: комментарий от alysnix

а на си эту «совершенно однозначную функцию» сделать нельзя что-ли?

Можно, но однозначность будет под вопросом, если функция достаточно сложная. Чтобы убедиться в однозначности императивщины придётся проверить абсолютно все комбинации входных состояний, и этих комбинаций могут быть миллиарды. Ну или при написании просто получится кусок лиспа, т.е. произойдёт переизобретение велосипеда.

Функциональщина далеко не во всех случаях применима, разумеется, но там где её применять уместно, она неплохо справляется.

Stanson ★★★★★
()
Ответ на: комментарий от anonymous

Вот с этим словоблудием теоретического программирования - к кому-нибудь другому, кто согласится потеоритизировать про «чистые функции», «функторы», «монады» и прочую срань придуманную чтобы звучало загадочно и ничего делать не заставляли.

Stanson ★★★★★
()
Ответ на: комментарий от Stanson

Если все будут придумывать термины как ты, то люди просто перестанут понимать друг друга. Если тебе не нравится термин, то тогда бог с тобой!

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

Похоже, что зря я сюда заглянул за ответом. Ожидал большего

anonymous
()