Обновить
1

Специалист по теории типов USB-кабелей

1,4
Рейтинг
30
Подписчики
Отправить сообщение

криптография 2004-2006 года - это старый и сложный код?

Старый, но несложный.

все прекрасно собралось

Добавьте оптимизации:

% g++ -v |& grep "gcc version"
gcc version 14.2.1 20241221 (Gentoo 14.2.1_p20241221 p7)
% g++ -Wall -Wextra -O3 -DDERS_CPU=cpu -c key.cpp
[...]
In file included from uint.hpp:22,
                 from key.hpp:19,
                 from key.cpp:11:
In destructor 'sh_ptr<T>::~sh_ptr() [with T = UInt]',
    inlined from 'void Key::computeRemainders(ShUInt, int, std::vector<sh_ptr<UInt> >&)' at key.cpp:57:1:
sh_ptr.hpp:93:30: warning: '*(sh_ptr<UInt>::Rep*)<unknown>.sh_ptr<UInt>::Rep::refs' may be used uninitialized [-Wmaybe-uninitialized]
   93 |       ~sh_ptr() { if (--rep->refs==0) delete rep; }
      |                         ~~~~~^~~~

и отлично работает!

Не могу проверить, потому что хз с чем это запускать вообще.

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

else return ShUInt();  // NULL

вызывает сначала конструктор sh_ptr<UInt> с нулевым указателем ptr, а потом его удаляет через в итоге fixed_alloc::free(ptr), который…

      static void free(void* ptr)
      {
       fixed_alloc_private::void_alloc<SIZE>::free(ptr);
      }

, который…

       static void free(void* ptr)
       {
        *(void**)ptr=head;
        head=ptr;
       }

Ой-вей, поздравляю с записью по нулевому указателю.

ЗЫ

ЗЫ — чувак написал 1400 строк кода, из которых треть — переизобретение своего наколенного boost::shared_ptr и прочего подобного, в которых сходу находятся ошибки, и пытается этим опровергнуть наличие проблем с миграцией на новые компиляторы у тех, кого строк кода не 1400, а 140000000.

Это, конечно, смешно.

может дело немножно в руках?

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

Детская травма от необходимости явно писать типы нетривиальных match-конструкций в определении функций, когда ну вот же оно тут написано прямо в типе функции ну что ты петух тупой что ли блин.

За счёт того, что в агде паттерн-матчинг сделан ну вот прям в определении функций, там это всё куда лучше выглядит.

Что, конечно, не отменяет куда более лучшей автоматизации в коке, поэтому имеем то, что имеем.

Спасибо, но я все еще не понимаю, а где хранится FallbackState для каждого энкодера в системе?

Он хранится для каждого созданного «экземпляра» fallback-энкодера в замыкании соответствующей функции. Каждый раз, когда я пишу

encoder ← swFallbackEncoder vp9hw vp9sw

то у меня «запускается» тело swFallbackEncoder, которое создаёт (newIORef) мутабельную переменную (isFallback), где лежит FallbackState (CanUseHW по умолчанию), и возвращает лямбду, которая на каждый фрейм проверяет эту захваченную переменную.

На плюсах это выглядело бы примерно как

auto swFallbackEncoder(auto hw, auto sw)
{
  auto shouldFallback = std::make_shared<bool>(false);
  return [=](VideoFrame frame)
  {
    if (*shouldFallback)
      return sw(frame);
    auto res = hw(frame);
    if (!res)
    {
      res = sw(frame)
      *shouldFallback = true;
    }
    return res;
  };
}

Вот эта mkEncoder она могла вернуть fallback врапер, а могла просто энкодер. Как вы потом ее результат вызваете?

Как функцию :]

runWithConfig config = do
  maybeEnc ← mkEncoder (encoderName config)
  case maybeEnc of
    Nothing → putStrLn "uh oh"
    Just enc → enc frame -- вызываю!

Можно написать тестовый код вроде

vp9swEncoder :: IO (Maybe Encoder)
vp9swEncoder = pure $ pure $ \frame → putStrLn "doing sw..." >> pure (Right $ show frame)

vp9hwEncoder :: IO (Maybe Encoder)
vp9hwEncoder = pure $ pure $ \frame → putStrLn "trying hw…" >> pure (Left "unable to encode")

и потом

main :: IO ()
main = do
  -- лень проверять just/nothing, я знаю, что там just
  Just enc1 ← mkEncoder "vp9"
  Just enc2 ← mkEncoder "vp9"
  enc1 10 >>= print
  enc1 11 >>= print
  enc2 20 >>= print
  enc2 21 >>= print

выведет

trying hw…
doing sw...
Right "10"
doing sw...
Right "11"
trying hw…
doing sw...
Right "20"
doing sw...
Right "21"

обратите внимание — trying hw для каждого отдельного энкодера печатается только раз.

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

Зачем для этого класс? Какой у него стейт? Могу ли я один инстанс класса DisplayFormatter дёргать из разных тредов? Могу ли я разные инстансы дёргать из разных тредов? Эквивалентен ли DisplayFormatter, отформатировавший сто юзеров, свежесозданному?

А можно просто сделать чистую функцию formatUser : User → String, и там этих вопросов нет. И передавать эти функции как аргументы другим функциям (если очень хочется звучать умно, можно это тоже называть DI).

Ну давайте упрастим и возьмем ваш тривиальный пример.

Я другой оратор и у меня другой тривиальный пример, я его ниже написал.

Блин, извините, я идиот, зачем-то флаги держу, когда можно без флагов, и просто в стейте хранить саму функцию, которую надо вызывать. Так гораздо чище, и в кои-то веки пригодился Control.Monad.mfix:

swFallbackEncoder :: Encoder → Encoder → IO Encoder
swFallbackEncoder hwEncoder swEncoder = do
  runner ← mfix $ \runner → newIORef $ \frame → hwEncoder frame >>= \case
    Right bs → pure $ Right bs
    Left err → writeIORef runner swEncoder >> swEncoder frame
  pure $ \frame → readIORef runner >>= ($ frame)

В коде ключевые слова class, instance... Ну допустим это другое.

Это действительно другое.

class — это обобщение ООПных интерфейсов или плюсовых концептов. Концепт «итератор» был бы классом. «Моноид» на самом деле является классом. «Любая монада, поддерживающая возможность хранить стейт типа Foo», является классом.

Инстанс — это объявление, что данный тип соответствует данному интерфейсу/концепту, и реализация требуемых интерфейсом/концептов методов/типов.

Часть — код редактора (который определяет тайпкласс Tool,и непоказанная часть по использованию, потому что грузить экзистенциалами читателя не стоит). Часть — код клиентов (определяющих конкретные тулы, это каждая пара data/instance).

Соседние ораторы показали много разных сложных примеров, а я покажу рабоче-колхозно:

type EncodeResult = Either Error BitStream
type Encoder = VideoFrame → IO EncodeResult

-- создаёт энкодер, загружая libvpx и потенциально фейлясь
vp9swEncoder :: IO (Maybe Encoder)
vp9swEncoder = undefined

-- ну дрова уж точно могут зафейлиться при инициализации
vp9hwEncoder :: IO (Maybe Encoder)
vp9hwEncoder = undefined

data FallbackState = CanUseHW | ShouldFallback

swFallbackEncoder :: Encoder → Encoder → IO Encoder
swFallbackEncoder hwEncoder swEncoder = do
  isFallback ← newIORef CanUseHW
  pure $ \frame → readIORef isFallback >>= \case
    ShouldFallback → swEncoder frame
    CanUseHW → hwEncoder frame >>= \case
      Right bs → pure $ Right bs
      Left _ → writeIORef isFallback ShouldFallback >> swEncoder frame

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

И в ООП вы или создаете VP8SWEncoder или H265HWEncoder или SoftwareFallbackEncoder(VP9SWEncoder, VP9HWEncoder). А потом просто вызвыаете Encode() у инстанса не думая о том, какой зоопарк кодеков у вас на самом деле.

А в чём вопрос? Просто возвращаете функцию.

mkEncoder :: String → IO (Maybe Encoder)
mkEncoder "vp9" = do
  vp9swResult ← vp9swEncoder
  vp9hwResult ← vp9hwEncoder
  case (vp9hwResult, vp9swResult) of
    (Just vp9hw, Just vp9sw) → pure <$> swFallbackEncoder vp9hw vp9sw
    (_, _) → pure $ msum [vp9hwResult, vp9swResult]
mkEncoder "vp9:force-sw" = vp9swEncoder
mkEncoder "vp8" = vp8swEncoder
mkEncoder "h265" = h265hwEncoder
mkEncoder _ = pure Nothing

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

Звучит снова как ФП.

Я читал Domain Modeling Made Functional, и читал более классическую книгу Эванса. Если в первой всё было просто и понятно, хоть сейчас устраивайся в кровавый тырпрайз, то после второй я, по-моему, стал понимать даже меньше.

class Tool t m where
  processPick :: t → Ctx → Point → m ()
  handleSelection :: t → [Object] → m ()

data BackdoorCCP = BackdoorCCP
  { address :: String
  , port :: Int
  }

instance Tool BackdoorSendToCCPServers IO where
  processPick bd _ p = sendToCCP bd $ "User clicked at " <> p
  handleSelection = ...

data FilterClicks base = FilterClicks
  { filterPred :: Ctx → Point → Bool
  , baseTool :: base
  }

instance Tool t m => Tool (FilterClicks t) m where
  processPick FilterClicks{..} ctx p
    | filterPred ctx p = processPick baseTool ctx p
    | otherwise = pure ()
  handleSelection = ...

data TestSpy = TestSpy

instance Tool TestSpy (WriterT [(Point)] m) where
  processPick _ _ p = tell [p]
  handleSelection = ...

Как один из кучи вариантов.

isabelle/hol

Мне не зашло, но люди пользуются (а меня и от кока чё-т тошнит).

Да один фиг, даже обычное сожительство тоже переоценено.

На удалёнке от 10 до 30 тысяч долларов на руки, нафиг эти ваши офисы?

Функциональное программирование более гибкое, соглашусь. Податливо, как пластилин. Очень удобно для научных задачек и сольного программирования. НО ЗАВОДЫ ИЗ ПЛАСТИЛИНА НА СТРОЯТ.

Ага. Именно поэтому верифицированное ядро SeL4 в первую очередь сделано на хаскеле (с полуэкстракцией в C). Или поэтому смарт-контракты с требованиями доверия им делаются на хаскеле и верифицируются на коке/изабелле/етц.

Хаскель не предлагать как язык широкого применения не проходит

Почему не подходит? Вполне применяю его широко, от написания на нём компиляторов до перекладывающих жсоны опердней.

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

Или, более кратко, «брак переоценен».

На самом деле тут надо бы ещё как-то демонстрировать своё отношение к этим книгам, потому что прочитанный и стоящий на полочке Поппер или Фукуяма ничего не говорят о том, насколько вы с ними согласны.

А потом разбираться с партнером по теме, с чем ты «сексуально взаимодействуешь» больше с работой или с ним/ней/ними? 

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

И почему это нельзя работать на буржуазию и одновременно обличать ее?

Можно, законы физики не запрещают. Но этически некрасиво.

Информация

В рейтинге
1 839-й
Зарегистрирован
Активность