LINUX.ORG.RU

Сообщения slovazap

 

Оптимальное размещение дерева на плоскости

Форум — Development

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

Например (слева просто дерево, справа с выполнением требования о близости сгруппированных вершин):

  1|x  3 5|x  7         7  5|x 1|x 3  (иксы рядом)
    \ /    \ /           \ /    \ /
    2|y     6     8|y     6     2|y    8|y  (игреки рядом)
      \     |     /        \     |     /
       \    |    /          \    |    /
        \   |   /            \   |   /
         \  |  /              \  |  /
          \ | /                \ | /
           \|/                  \|/
            4                    4

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

Есть ли название у этой задачи, какие есть пути решения?

Пока идеи такие:

  • Можно решать чисто от порядка вершин, т.е. ввести меру расстояния между двумя вершинами с одним тэгом (= число вершин между ними без этого тэга), и минимизировать сумму таких расстояний для всех пар. Чем такое можно делать (алгоритмы, библиотеки)? Быстрее чем за факториал, понятное дело.
  • Можно решать от размещения вершин на плоскости
    • Планаризация графа, причём довольно хитрая - вводим новые рёбра так чтобы вершины с одним тэгом образовали полный граф, и планаризируем (алгоритмы, библиотеки?) учитывая только пересечения новых рёбер с рёбрами дерева с весом 1 и рёбер дерева между собой с бесконечным весом.
    • Модель пружинок и зарядов, но кажется что чтобы она сошлась нужно начать с чего-то подготовленного одним из способов выше.

 , ,

slovazap
()

Отвадить птиц от окна

Форум — Talks

Задолбали синицы - жрут монтажную пену вокруг окна и разбирают москитную сетку. Нахрена им это нужно? Есть рецепты как их отвадить? Стрелять из пневматики или травить не очень хочется.

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

slovazap
()

Актуальные настройки для ffmpeg пря перекодировки видео

Форум — Multimedia

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

GoPRO снимает в этом: VIDEO: [H264] 1920x1080 24bpp 23.976 fps 29970.6 kbps (3658.5 kbyte/s)

Нужно наверное не больше 720p, а скорее даже 480p, современный кодек (H265?), и настройки учитывающие что это видео с gopro с резкими мотаниями в стороны. Суть видео - разный активный отдых, типа рабылки, катания на мотоциклах-лодках, ныряния.

 ,

slovazap
()

Телефон под LineageOS

Форум — Talks

Умер Wileyfox Swift, который брал специально для установки туда CyanogenMod, и счастливо 3 года использовал. Можно, конечно, купить такой же, только он уже не продаётся и специально искать не охота, да и смысла нет при наличии более современных и чем-то, наверное, более лучших девайсов. В связи с этим призываются пользователи CyanogenMod или её преемников с саксесс стори по девайсам.

Во-первых, как LineageOS? Я правильно понимаю что это преемник именно CyanogenMod (а не CyanogenOS, кажется в последней было что-то мне сильно не нужное). Во-вторых, какой брать девайс? Требований к железу нет - 1 симка, 1 microsd, если камера получше чем в swift то плюс, более ёмкий аккумулятор тоже плюс, остальное пофик, цена соответственно 5к±.

Да и ещё расскажу о известных мне проблемах в swift (цианоген там 13.0, обновлять было лень, тем более после того как он чуть не брикнулся при OTA обновлении), интересно как с ними в новых версиях или других девайсах.

  • GPS работает только когда активно приложение его использующее. Т.е. запустил SatStat, местоположение нашлось, всё зашибись, но переключился в другое приложение - фикс сразу пропал, будет заново искать. Из браузера, скажем, из яндекс.карт, местоположение найти вообще не успевает. Есть приложения которые нормально работают, но видимо они что-то специально для этого делают. Хотелось бы чтобы GPS не выключался вообще если нужен фоновым приложениям и, скажем, минуту если не нужен никому.
  • Не работает запись звонков в Call Recorder из F-Droid, т.е. записывается только мой голос, не собеседника. Пишут что это нормально, но вдруг у кого-то где-то заработало.

 

slovazap
()

Правильная организация подразделов сайта

Форум — Web-development

Есть сайт, на нём продукты (мои СПО поделки), для каждого продукта есть несколько разделов. Примерно так:

site.com/podelka1/news
site.com/podelka1/screenshots
site.com/podelka1/download
site.com/podelka2/news
site.com/podelka2/screenshots
site.com/podelka2/download

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

Вопрос: как правильно организовать обработку урла site.com/podelka1 с точки зрения HTTP, поисковиков, кэшей и т.д.? Вижу такие варианты:

  • Сделать редирект (site.com/podelka1 -> site.com/podelka1/news, например). Совершенно не понимаю точно какой тип редиректа тут подойдёт:
    • Точно не 301, потому что это не перемещение страницы, его не нужно запоминать навсегда, и оно развязало бы руки вебмастерам заменить короткую ссылку длинной.
    • 302 типа замещён 303 и 307 из-за размытого значения. Ок, допустим.
    • 303 подходит по названию, но на деле в описании что-то страшное про перезапрос GET методом после POST/PUT/DELETE. Шо?
    • 307 не очень нравится определение, поскольку это же не moved и не temporary. Это диспетчеризация трафика извне и временность/постоянность её не отличается от оной на любых других страницах сайта. В частности, редирект можно и нужно кэшировать как указано в соответствующих заголовках.
    • Или может всё-таки, 302 как раз в силу его неопределённости мне лучше всего и подойдёт?
    Ещё один важный аргумент - потеря Google PR. [1] пишут что раньше 3xx кроме 301 теряли ссылочный вес полностью, потом де это пофиксили. Но всё равно редирект считается за переход по ссылке, значит теряет 15% веса. Но это не точно. И про 303 ничего толком не сказано.
  • Сделать дубликат страницы (т.е. /podelka1 возвращает то же самое что, например, /podelka1/news) + <link rel=canonical>. С поисковиками проблем вроде уже не будет, зато приведёт к дубликатам у пользователей.
  • Сделать обратный редирект, т.е. оставить новости на site.com/podelka1 и сделать редирект с site.com/podelka1/news? Вроде убирает технические проблемы, но ломает структуру сайта.
  • Ещё варианты?

[1] https://moz.com/blog/301-redirection-rules-for-seo

 , , ,

slovazap
()

Легковесный web фреймворк с удобными формами

Форум — Development

Юзкейс следующий: сайт контент на котором добавляют пользователи. Соответственно для каждого объекта на сайте нужна кнопочка edit за которой скрывается форма редактирования. Ну и аналогичная форма добавления рядом.

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

Я привык к flask и по случаю освоил sqlalchemy, и покрутил wtforms, но ощущение от них преотвратное - всё нужно связывать изолентой и дописывать руками. Хочется MVC из коробки. Поэтому ищется другой фреймворк где с этим будет проще. Для питона, но для других языков я бы тоже посмотрел ради общего развития. Смотреть на django?

 , ,

slovazap
()

Питон, автоимпорт коллекции модулей

Форум — Development

Есть коллекция модулей, по сути это разные обработчики с одним интерфейсом.

processors/foo.py:
class FooProcessor:
    ...

processors/bar.py:
class BarProcessor:
    ...

processors/baz.py:
class BazProcessor:
    ...

processors/__init__.py:
from .foo import FooProcessor
from .bar import BarProcessor
from .baz import BazProcessor

И испольузется это так:

from processors import *

def spawn(name):
    classname = name + "Processor"
    return globals()[classname]()

spawn("Foo")

Так вот, надоело все процессоры регистрировать в __init__.py, криво это да и всякие линтеры ругаются на неиспользуемые модули.

Вопрос: как это сделать красиво?

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

Наверное можно в spawn руками импортировать модуль по имени, но имя класса не всегда совпадает с именем модуля (и в модуле может вообще быть несколько классов).

Наверное можно запихнуть все модули в modname/__init__.py, но это неудобно и криво.

Наверное можно в processors/__init__.py перебрать модули в processors и импортировать их все - есть пример как это сделать?

Может есть ещё красивее способ?

 , ,

slovazap
()

Архитектура database API класса

Форум — Development

Есть приложение на питоне, использует psycopg.

Есть класс для работы с базой, который инкапсулирует весь SQL код и предоставляет API. В частности, там есть метод для создания схемы, есть методы для чтения и записи определённых данных в/из базу. Условно это выглядит как-то так:

class Database:
    def __init__(self, dsn):
        self.db = psycopg2.connect(dsn)

    def CreateSchema(self):
        self.db.cursor().execute("CREATE TABLE foo ...")
        ...

    def GetFoo(self, id):
        cur = self.db.cursor()
        cur.execute("SELECT...JOIN...JOIN...FROM SELECT(...)...GROUP BY...ORDER BY)

        return [ MyFooObject(a=row[0], b=row[1], c=row[2] for row in cur.fetchall() ]

Этот класс уже разросся на несколько тысяч строк, поскольку методов API накопилось много, посему вопрос: какие best practices есть по разбивке его на небольшие части? Навскидку придумывается только что-то такое:

class FooAPI:
    def __init__(self, db):
        self.db = db

    def Get(self, id):
        self.db.cursor()
        cur.execute("SELECT...JOIN...JOIN...FROM SELECT(...)...GROUP BY...ORDER BY")

        return [ MyFooObject(a=row[0], b=row[1], c=row[2] for row in cur.fetchall() ]

class Database:
    def __init__(self, dsn):
        self.db = psycopg2.connect(dsn)

    def GetFooAPI(self):
        return FooAPI(db)

но как-то это топорно.

PS. ORM, естественно, не предлагать.

 , ,

slovazap
()

Железа под роутер совета тред

Форум — Talks

Хочу купить себе домой железку под роутер. Сейчас трудится раздолбанный третьепень + отдельно свич и точка доступа. Программа-минимум - заменить нафиг третьепень, поскольку он занимает место, скрипит кулерами, жрёт электричество, собирает пыль, убого выглядит и вообще на ладан дышит. Нужна, соответственно, железка как минимум с 2 100Mbit портами, с пассивным охлаждением, и полноценная в плане производительности (поскольку нужны всякие штуки типа вложенных VPN, IPv6, терминации DNS туннелей, сквида и т.д., т.е. в огрызке типа openwrt на каком-нибудь mips роутере это сначала замучаешься настраивать, а потом окажется что процессор не тянет шифрование). А программа-максимум - 4+ Gbe порта и встроенный wifi, чтобы заменить свич и AP соответственно. Торренты на ней не нужны (и сквид будет без кэша), поэтому компактный корпус без места под доп. диски - плюс.

То что нужно можно описать как Intel NUC, только с 4 ethernet и ваем. Или что-то типа Archer C7, только с нормальными мозгами. Может какой-нибудь ARM одноплатник помощнее есть?

 , ,

slovazap
()

Правильный multiprocessing pool на python

Форум — Development

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

Итого, нужно в основном процессе выгребать данные, отправлять worker'ам, получать от worker'ов результаты и складывать в базу. Как это лаконичнее всего организовать на питоне?

Первая идея была использовать готовый Pool. Написал тестовую прогу:

import multiprocessing
import sys
import time

def Process(arg):
    print("processing {}".format(arg), file=sys.stderr)
    time.sleep(1)
    return 10000 + arg

def Generate():
    for val in range(1000):
        print("generating {}".format(val), file=sys.stderr)
        yield val

if __name__ == '__main__':
    pool = multiprocessing.Pool(10)

    for res in pool.imap(Process, Generate(), 1):
        print("finalizing {}".format(res), file=sys.stderr)

    pool.close()
    pool.join()

На практике, понятно, в Generate() будет чтение из базы, а в цикле по imap - запись.

Вроде всё зашибись, кроме того что все 1000 значений генерируются в начале программы. На практике это будет означать что программа сразу выгребет из базы кучу данных и выжрет всю память. Причём если в Generate поставить sleep то всё хорошо, обработчики будут ждать данных, но на практике они работают медленнее базы. Обернуть в какую-нибудь lazy штуку не получится, потому что тогда она будет выполняться в worker процессе где не будет подключения к бд. Что можно сделать чтобы imap просил следующую порцию данных только когда у него есть свободный процесс или место в (ограниченной) очереди для её обработки?

Или придётся всё писать руками? Руками создавать N процессов, две очереди (для заданий worker'ам и для ответов от них)? Тогда я не могу придумать как красиво обрабатывать эти две очереди, поскольку нужен аналог select'а, иначе получим дедлоки. Вырисовывается такой уродец:

tasks_in_fly = 0

while True:
  task = get_next_from_db();

  if not task:
    # задания закончились
    break

  try:
    # нельзя просто put, иначе получим deadlock если обе очереди заполнены
    task_queue.put_nowait(task)
    tasks_in_fly += 1
  except queue.Full:
    # если места в очереди нет, нужно разобрать ответы
    try:
      while True:
        # выгребать ответы пока очередь не опустеет и не кинется исключение
        result = result_queue.get_nowait()
        tasks_in_fly -= 1

        put_to_db(result)
    except queue.Empty:
      pass

# и ещё нужно дождаться последних ответов и оработать их
while tasks_in_fly:
  result = result_queue.get()
  tasks_in_fly -= 1

  put_to_db(result)

Если только так, может есть идеи как этот код улучшить?

 , ,

slovazap
()

Сравнивалка версий пакетов repology.org

Форум — Talks

Видели сабж? Интересно было бы услышать мнения почему «RIP» FreeBSD которую почти никто не использует занимает второе место по количеству и свежести пакетов, уступая только дебиану?

 , , versions

slovazap
()

Web морда для простой базы

Форум — Development

Для web я последний раз серьёзно писал на перле лет десять назад, после только простые сайтики без динамического бэкэнда. Собственно вопрос - во что сейчас имеет смысл вникнуть чтобы написать простую stateless морду для небольшой базы (десятки тысяч записей; достаточно маленькая чтобы целиком влезть в память, но слишком большая чтобы отдать всю в .json'е клиенту). Нужно всего навсего листать эту базу по страничкам с некоторыми фильтрами, искать по подстроке в одном поле и для конкретных записей генерить svg картинки, которые видимо, понадобится кэшировать. Крутиться будет на небольшом VPS (1 ядро, гиг памяти). База read-only, но периодически обновляется batch'ем вся целиком.

1. Язык. Что сейчас есть для не слишком навороченного и требовательного бэкэнда? Думаю взять питон, потому что перл во-первых, забыл, во-вторых, как ни крути он read only. Ещё варианты? node не хочу из-за уродливой и небезопасной системы модулей.

2. База. Взять mysql и не париться? Или какой-нибудь новомодный NoSQL может оказаться даже проще в моём случае? Или даже вообще без базы (см. 3)?

3. Как собственно организовать бэкэнд? CGI как я понял это прошлый век, да и отдельный апач для них поднимать неохота (nginx уже работает). Имеет право на жизнь вариант когда бэкэнд просто слушает по HTTP и проксируется nginx'ом? В таком случае я бы и mysql не поднимал, а просто загрузил всю базу в память.

Если рассуждения правильные, посоветуйте модулей/фреймворков для питона на которых это будет просто реализовать. Если база в памяти, нужен, по сути, только производительный HTTP сервер и простой фреймворк для диспатчинга запросов, возможно шаблоны (на слуху jinja2?).

 ,

slovazap
()

Что сейчас с хоть чуть-чуть безопасным андроидом?

Форум — Mobile

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

Говорят что девайсов без залочки понаплодилось прилично, тот же wileyfox с цианогеном из коробки и задёшево, поэтому мой главный вопрос - о изоляции. Умеет ли сейчас андроид/цианоген не просто показать что нужно приложению (доступ к сети, флешке, GPS и виброзвонку) и предоставить выбор только между «согласиться» или «вообще не ставить приложение», а регулировать права гранулярно: в худшем случае просто разрешать/не разрешать отдельные доступы, в лучшем - уметь предоставлять приложению фейковые данные (неработающую вибру, [0.0, 0.0] GPS, доступ к сети в котором ни один сайт не отвечает, ФС где каждый файл открывает /dev/null), а также регулировать доступ к отдельным сайтам/url и директориям на флешке.

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

Перемещено leave из talks

 , ,

slovazap
()

Endless Sky

Форум — Games

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

http://endless-sky.github.io/

2D космическая леталка. Исследуем галактику перемещаясь между звёздными системами, зарабатываем бабло торговлей, перевозом грузов и пассажиров, отловом пиратов, или сами грабим корованы (можно брать корабли на абордаж, снимать груз и оборудование, либо вообще захватывать их целиком). На деньги покупаем более крутые корабли (вплоть до авианосцев) и оборудование, а потом можно вообще сколотить свой флот. Выполняем побочные квесты или идём по основной сюжетной линии (которая офигенна, огромна и включает терроризм, сепаратистов, общегалактическую гражданскую войну, альянсы и предательства, по меньшей мере двукратное объединение перед лицом общего врага, политические и дипломатические интриги, открытие новых технологий, таинственные угрозы и загадки глубокого космоса и прошлого человечества, другие расы и всё это переплетено с судьбами отдельных людей. Романтической линии разве что не хватает, хотя может я до неё просто не добрался).

Играю вторую неделю и до конца пока не добрался, всем советую.

 , ,

slovazap
()

Нечёткая сортировка

Форум — Development

Есть многоугольники на плоскости. Нужно отрисовать это как сцену в изометрии - вытянуть многоугольники в высоту получив призмы. При этом нужно рисовать их в правильной последовательности, чтобы ближние закрывали дальние. OpenGL и z-buffer использовать нельзя. Разбивать призмы нельзя, т.е. выводить каждую только целиком. Порядок призм по условию задачи определяется довольно хитрым образом: о двух призмах мы можем сказать: либо А ближе Б, либо Б ближе А, либо порядок не важен. Причём эта операция не коммутативна: А может считать себя ближе Б, но Б может считать что пересекается с А. Понятно, что в этих условиях некоторые случаи невозможно нарисовать корректно (например, пересекающиеся призмы, или призму в выемке другой, невыпуклой), а некоторые можно нарисовать разными способами (из-за хитрого сравнения) - это нормально.

Собственно вопрос - чем это сортировать. Понятно что стандартный std::sort даст скорее всего непредсказуемые результаты, да и работает он с бинарным предикатом, а нужен тернарный. Кроме этого, сортировка нужна стабильная и эффективно сортирующая (почти) отсортированную последовательность, ибо есть идея при изменении сцены/позиции наблюдателя использовать сортировку с предыдущего кадра которая почти всегда будет подходить в неизменном виде.

Можно было бы использовать самые банальные алгоритмы начиная с пузырька, учитывая что для отсортированной последовательности он даст O(n), но меня беспокоит нестабильность на штуках типа А < Б, Б < В, В < А которые по условию тоже возможны.

 ,

slovazap
()

Как всё-таки работать с сырыми байтами?

Форум — Development

Есть некий бинарный файл, хранит 32битные значения (signed и unsigned) и ascii строки. Как-то попадает в память (может ifstream::read, или mmap). Вопрос в том, как их него правильно читать значения не нарвавшись на undefined behavior, а желательно - и на implementation-specific behavior.

Для начала, просто unsigned и строки.

Вобщем-то, вопрос сводится к тому, в каком типе хранить данные. С одной стороны, тот же ifstream::read возвращает char*. С другой, std::string конструируется также из char*. Но с третьей, чтобы безопасно кросс-платформенно читать инты (побайтовое чтение + сдвиги + OR), нужен беззнаковый тип, потому что сдвиг знакового ЕМНИП UB. Каст знакового в беззнаковое, опять таки ЕМНИП, implementation defined. Остаётся только касты между unsigned char* и char*, что с ними - будет ли ub или implementation-defined? Если будет, что делать? Я больше вариантов не вижу.

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

 , ,

slovazap
()

Вопросы по boost::spirit

Форум — Development

Начал изучать сабж. Пару раз бросал и садился писать свой парсер, но, как ни крути, spirit получается удобнее. Только вот по нему нет нормальной документации и примеров, поэтому не остаётся ничего кроме как спросить здесь.

Первое, собственно, посоветуйте нормальных примеров вместо фуфла с офсайта, которое покрывает только самые тривиальные случаи использования.

Далее конкретные вопросы.

Есть парсер списка команд вида

FOO 1, 2, 3
BAR 1, 2, "ARG3"
BAZ 2, 0.5, "ZZZ"

парсит их в структуры вида

struct cmdfoo {
  int arg1;
  int arg2;
  int arg3;
};

структуры нужно запаковать в набор векторов в другой структуре

struct cmdlist {
  std::vector<cmdfoo> foos;
  std::vector<cmdbar> bars;
  std::vector<cmdbaz> bazs;
}

В целом, на BOOST_FUSION_ADAPT_STRUCT это хорошо ложится, но есть исключения.

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

BARa 1, 2, 3
BARb 1, 2, 4

struct cmdbar {
  enum { A, B } type;
  int arg1;
  int arg2;
  int arg3;
  int arg4;
};

Что с этим делать? Во-первых, не хочется дублировать правило грамматики для парсинга очень похожих штук. Во-вторых, как использовать BOOST_FUSION_ADAPT_STRUCT чтобы было 2 adapt'а для одной сруктуры? Видел BOOST_FUSION_ADAPT_STRUCT_NAMED, но как сказать правилу которое

qi::rule<Iterator, cmdbar()>, foocmda_rule;

использовать конкретный adapt?

Во-вторых, в грамматике, очевидно, будет общее правило для любой команды:

cmd_rule = cmdfoo_rule | cmdbar_rule | cmdbaz_rule;

Я видел что в таких случаях возвращают boost::variant, но не хочется паковать правила в вариант, а выше по грамматике распаковывать чтобы распихать по векторам. Можно как-то достучаться из правил-листьев до верха, т.е. правила которое генерирует cmdlist?

Это пока основное что мне не понятно.

 , , ,

slovazap
()

Правильное версионирование библиотек

Форум — Development

Пишу я shared библиотеку. Кажется другие люди начинают её потихоньку использовать да ещё добавлять в дистрибутивы, поэтому решил заморочиться стабилизацией API и правильным версионированием, чтобы при обновлении библиотеки ни у кого не возникало проблем. Напомню что библиотека устанавливается в виде libfoo.so.X.Y.Z, на неё ставятся симлинки libfoo.so и libfoo.so.X, в SONAME прописывается libfoo.so.X

Вопросы:

  • Когда нужно увеличивать X - только при поломке обратной совместимости ABI или даже при обратно совместимых изменениях? Если второе, почему и при каких условиях тогда изменяется Y?
  • Что делать с Y.Z? Почитал, понял что их трактуют кто во что горазд - кто как в semantic versioning (Y - обратно совместимые изменения ABI, Z - изменения не влияющие на ABI), кто (libtool) вообще странно, Z у него это некий age, который показывает сколько мажорных версий назад от X поддерживает библиотека (т.е. типа 5.0.2 поддерживает 5, 4, 3). Вроде бы про Y разночтений нет, поэтому думаю использовать его для совместимых изменений ABI, а Z всегда ставить в 0
  • А не стоит ли тогда вообще выкинуть Z?
  • Как часто имеет смысл обновлять версию? С релизом, или на каждый коммит, изменяющий ABI?
  • Чисто ради интереса, есть практичиская разница между вариантами когда .so ссылается на .so.X (так делает cmake) или на .so.X.Y.Z (так делают autotools)?

 , ,

slovazap
()

Stringify выражения в unit тесте

Форум — Development

Хочу написать небольшой велосипедный unit test фреймворк, требования следующие: во-первых, нужно чтобы в выхлопе теста фигурировало тестируемое выражение, во-вторых, у тестов должны быть опциональные аргументы, например описание. Пример (ASSERT, понятно, проверяет выражение на истинность):

int main() {
  ASSERT(true && true && true);
  ASSERT(true && true && true, "is always true");
  ASSERT(true && false);
  ASSERT(true && false, "is actually false");
}

выдаёт

passed: true && true && true 
passed: true && true && true (is always true)
failed: true && false
failed: true && false (is actually false)

Вопрос как это реализовать. Т.к. нужен stringify выражения, понятно что без макросов не обойтись. Но с макросами проблема в невозможности перегрузки и дефолтных зрачений (чтобы не нужен было указывать каждый раз все опциональные аргументы).

Есть variadic macros, но #define ASSERT(expr, ...) my_overloaded_function(#expr, expr, __VA_ARGS__) будет требовать хотя бы одного опционального аргумента, что не хочется. Есть ##__VA_ARGS__, которая эту проблему решает, но это GNU расширение.

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

 ,

slovazap
()

move semantics, как обрабатывать доступ к moved-from объектам?

Форум — Development

Проникся c++11, начал разбираться с move semantics. По ходу возник вопрос: могут быть ситуации, когда содержимое объекта перекочевало в другой посредством move, и объект остался «пустым». Всё хорошо когда «пустое» состояние объекта валидно (например, пустой vector) и/или пустой объект сразу становится недоступен (если он был временный, например). Но если оба этих условия не выполняются, как быть? Скажем, я пишу библиотеку, у меня есть какой-то класс, у объектов которого не бывает валидного пустого состояния, а пользователь библиотеки делает std::move из такого объекта него, а потом вызывает какой-то его метод. Нужно ли это предусмотреть и что в таких ситуациях делать? throw logic_error? assert? abort? ничего (UB)?

Мне пока кажется что с одной стороны, вроде самое правильное добавить assert'ы (громко падает в debug сборке и не тратит ресурсы на проверки в release), с другой - в каждый метод пихать проверку ой как не хочется.

 ,

slovazap
()

RSS подписка на новые темы