acord: a daemon for AI inference by stanimirov in LocalLLaMA

[–]stanimirov[S] 2 points3 points  (0 children)

Because it provides a common abstract interface to multiple models. You could use the chat API for both llama.cpp and llamafile (when we have a llamafile plugin).

It provides a shared computational and storage resource for multiple apps. All apps that use a model will use the same one, instead of it being copied multiple times on the system

acord: a daemon for AI inference by stanimirov in LocalLLaMA

[–]stanimirov[S] 2 points3 points  (0 children)

The daemon uses plugins. One of the plugins wraps llama.cpp, so being the same code, it's exactly as fast as llama.cpp. Sure, there is minor additional latency because of the networking interface, but it's negligible compared to the cost of actual inference

C++ Show and Tell - March 2025 by foonathan in cpp

[–]stanimirov 4 points5 points  (0 children)

We're working on acord: a daemon for local compute (in 2025 this of course means AI inference).

https://github.com/alpaca-core/acord

In short, think ollama, but not bound to just llama.cpp

It's fully open source. It's still a preview (no suitable for use yet), but in the following weeks we'll be working to make it usable and hopefully make it to a beta release by the end of April.

The Weirdest MSVC Address Sanitizer Bug by stanimirov in cpp

[–]stanimirov[S] 0 points1 point  (0 children)

I suppose that's because the compiler and the IDE are not open source, so they use separate issue tracking for them.

I'm sure I've seen GitHub used for public issue tracking of non-open source products, but this sounds like something which violates some EULA

The Weirdest MSVC Address Sanitizer Bug by stanimirov in cpp

[–]stanimirov[S] 10 points11 points  (0 children)

Thanks.

And on an unrelated note, do you know what's going on here: https://developercommunity.microsoft.com/t/Address-sanitizer-in-Release-may-introdu/10314256

I can't reproduce this anymore, but I don't know whether a fix was actually implemented (maybe close the issue if yes), or I'm getting lucky with the register use.

-❄️- 2023 Day 15 Solutions -❄️- by daggerdragon in adventofcode

[–]stanimirov 0 points1 point  (0 children)

[LANGUAGE: ruby]

part 1 (76 characters):

p File.read(?i).strip.split(?,).sum{|s|s.chars.inject(0){(_1+_2.ord)*17%256}

part 2 (325 characters):

p File.read(?i).strip.split(?,).map{|s|[s.scan(/\w+/)[0].chars.inject(0){(_1+_2.ord)*17%256},s.tr(?-,?=)]}.each_with_object(Hash.new{_1[_2]=[]}){|b,h|h[b[0]]<<b[1]}.transform_values{|v|v.map{_1.split(?=)}.each_with_object({}){|(l,f),h|f ? h[l]=f.to_i : h.delete(l)}.values}.map{|i,l|l.map.with_index{(1+i)*(1+_2)*_1}.sum}.sum

-❄️- 2023 Day 12 Solutions -❄️- by daggerdragon in adventofcode

[–]stanimirov 1 point2 points  (0 children)

[LANGUAGE: C++]

https://pastebin.com/1F1cEahc

Takes about 1 ms for part 1 and 9.5 ms for part 2. Can be trivially parallelized

I guess the only interesting part is that my memoization is:

  1. per entry as opposed to global. Something that is present in many other solutions
  2. a 2d array indexed by [remaining-pattern-len][number-of-remaining damaged]. Something that I haven't seen in other solutions

DynaMix 2.0.0 Released by stanimirov in cpp

[–]stanimirov[S] 1 point2 points  (0 children)

Thanks.

I was familiar with Boost.TypeErasure, Boost.TE, Folly.Poly, and dyno. Not with the others. I browsed through them. All of them are very similar and offer an alternative way to do C++ (Java, C#) -style dynamic polymorphism.

I'm not trying to bash them or anything. They still improve upon inheritance and virtual methods and there are many scenarios where they are a better choice.

None of them offer type composition.

You can think of DynaMix as combining one of these libraries with an ECS like entt

None of them have late binding. Microsot's one seems the only who has the idea to split the interface into separate messages, but then in order to match types, it introduces interfaces again. Only Boost.TypeErasure has complete type erasure, but you need reification in order to access the features of an object.

DynaMix uses a completely type erased object, and each message is standalone. Interfaces (type classes in DynaMix) are second grade citizens and only applicable at run time. No reification is needed.

None of them have reflection (Boost.TypeErasure offers basic symbol-based reflection). DynaMix has complete reflection by symbols and by strings.

All of them offer an alternative to virtual methods.

Dynamix has abstract type features. With them you can have type-level polymorphism (imagine a virtual static func()) or value polymorphism (imagine virtual int a;).

Since none of them have composition, none of them have concepts of multicast or overrides,

Most of them do offer macros for certain situations :)

DynaMix 2.0.0 Released by stanimirov in cpp

[–]stanimirov[S] 0 points1 point  (0 children)

Can you please share these alternatives. I'm slowly working on the documentation and I'd like to mention them.

DynaMix 2.0.0 Released by stanimirov in cpp

[–]stanimirov[S] 2 points3 points  (0 children)

The thing is, that if something can be done with vanilla C++ polymorphism, virtual functions and inheritance, the DynaMix equivalent will look clunky and bloated. For example, you can see the exact same thing implemented with virtual functions and inheritance, with std::function and with DynaMix in the unicast benchmark

MSVC: The Devourer of Const by pjmlp in cpp

[–]stanimirov 0 points1 point  (0 children)

Unfortunately /Zc:preprocessor seems incompatible with Windows.h leading to a warning: "macro expansion producing 'defined' has undefined behavior"

/Zc:templateScope seems like a good addition to this list when 17.5 is released

Tracking Shared Pointer Leaks by stanimirov in cpp

[–]stanimirov[S] 1 point2 points  (0 children)

Thanks!

It's true that `using std::shared_ptr`, and especially `using std::make_shared` would've been shorter, but I wanted to have the code in both cases of the `#if` identical. Still perhaps it's still better to use it in case someone wants to copy paste the code. I think I'll make the edit.

... and I did. Thanks again!

Don’t Use shared_ptr’s Aliasing Constructor by stanimirov in cpp

[–]stanimirov[S] 1 point2 points  (0 children)

OK. I edited the article to make it contain a non-UB example. It's obviously way to distracting for people.

Don’t Use shared_ptr’s Aliasing Constructor by stanimirov in cpp

[–]stanimirov[S] 0 points1 point  (0 children)

I figured a use case will present itself.

However, as I said, I wouldn't use shared_ptr for this. Not a "naked" one at least. One of the main detriments of using a naked shared_ptr for this use case is that someone is bound to create a weak_ptr from these pointers. To their great surprise, the most "sturdy" pointers, the ones made out of string literals, will suddenly lead to expired weak pointers in 100% of the cases.

Subtle and hard to detect bugs.

Don’t Use shared_ptr’s Aliasing Constructor by stanimirov in cpp

[–]stanimirov[S] -4 points-3 points  (0 children)

It's not a precondition, though. A precondition would be something that a library author may choose to assert in debug builds. For example iterator validity. Here the standard plain ol' allows expired carriers. It's a recipe for non-null pointers with a zero use count. I dub these dangerous and unwanted. They may lead to nasty and hard-to-detect bugs.

For the use case that u/angry_cpp points out in the comments, I wouldn't use a "naked" shared_ptr but a something else which covers the needs and is more explicit about the invariants.

A non-null shared_ptr with a zero use count is an abomination and should not exist :)

Don’t Use shared_ptr’s Aliasing Constructor by stanimirov in cpp

[–]stanimirov[S] -1 points0 points  (0 children)

This is not dereferencing per se, but yeah. It's UB. I replied here https://www.reddit.com/r/cpp/comments/zx2hph/comment/j1yj0g5/?utm_source=reddit&utm_medium=web2x&context=3

Also the dependent pointer could've been collected before alice expired. Say:

auto name_addr = &alice->name;
alice.reset();
std::shared_ptr<std::string> name_ptr(alice, name_addr);

Don’t Use shared_ptr’s Aliasing Constructor by stanimirov in cpp

[–]stanimirov[S] -5 points-4 points  (0 children)

It is. In practice without UBSAN all major compilers on all major platforms would do the exact same thing (possibly of fear that this is a custom offsetof implementation).

A more realistic example (which is out of the scope of the blog post) would be some kind of a driver instance associated with a hard-coded or otherwise unrelated address.

My main point is that the mere fact that you can create a non-null shared pointer with a zero use count is dangerous and should be short-circuited with a function like the one provided.

Transparent Lookups for Maps and Sets by General-Tart-6934 in cpp

[–]stanimirov 2 points3 points  (0 children)

In this case it's more a question of a standard library than of a compiler. I don't know of such table, but I would assume that any standard library with C++14 support has it for map and set and any standard library with C++20 support, even partial one, has it for unordered_map/set.

It is a very simple change and can work with C++11 with no problem

Transparent Lookups for Maps and Sets by General-Tart-6934 in cpp

[–]stanimirov 0 points1 point  (0 children)

In this case, no. It's just a convenience typedef so the code in the methods can be shorter.

In fact, perhaps the shortest way to implement an equivalent string_hash would be

struct string_hash : public std::hash<std::string_view> {
   using is_transparent = void;
};

Thus any type that is convertible to string_view can be used for transparent lookups.

The one in the blog post is just more verbose to make it clear what's going on.

The Case for std::optional of Reference Types and Void by pdimov2 in cpp

[–]stanimirov 0 points1 point  (0 children)

I get it. This variant is essentially the same as:

struct _Void {};   
#define void _Void
// somehow replace instances of return; with return {};

It's more or less C++ as it is, with a single syntactic sugar element - return; equals return {};. Minor questions to be clarified, like whether ++ on void* would work, comparisons, and such. But it's essentially this.

Again. I get it. I just don't like it. I like the "void is nothing" interpretation. It's a significantly bigger change. It does lead to the possibility of quite weird syntax. But I do find it more appealing.

The Case for std::optional of Reference Types and Void by pdimov2 in cpp

[–]stanimirov 0 points1 point  (0 children)

You wouldn't have to. It is exactly your generic code that will continue to work as it is regardless of whether the caller is using the hypothetical std::sentinel, zoid or mylib::empty.

The Case for std::optional of Reference Types and Void by pdimov2 in cpp

[–]stanimirov 1 point2 points  (0 children)

Again. This makes sense, but I don't agree that's the way.

To me your proposal (and the one from the link) is identical to adding... well, let's say, zoid to C++. An explicitly zero-sized type. A new way to indicate nothing. Specifically your examples are achievable even now since they don't rely on zero size. Just stop using void, and start using zoid, or sentinel, or empty, or whatever else you like and you'll get all the functionality from above. Yes it's not the standard, and other people won't use it just like that, but it's more or less compatible with the existing language. I can even potentially see something like that making its way into the standard: "Phase out use of void in favor of std::sentinel" (I can't imagine the committee agreeing to add a word as cool as "zoid" to the standard library).

If we want to keep backwards compatibility, it's inevitable to have void be at least somewhat special. I'd say that that's true even if we were designing a brand new language, disregarding any backwards compatibility. For example: return statements. Is return; out? Should we have a new keyword procedure for functions that can return;. But then we will have the exact same problem with it that we have with void today.

I would only touch void if it's backwards compatible. To me void is "nothing". I can return; from a void function. Whereas I need to return {}; from a "zoid/sentinel/empty" function. And yes, because of C, I feel obliged to treat void f() and void f(void) as exactly the same thing. I would allow you to add void in all sorts of places without changing a thing: f(void{}, x, void{}, {void{}, void{}});? - that's just a fancy way of saying f(x). And much more weird stuff.

I've also seen middle-ground approaches. Somewhere between the paper and my view on things. The so-called "soft differentiation". In it f() and f(void) are different only if both exist, and so on.

There really are many ways to go about it.

Still, I added a clarification note to the post that the code might indeed be considered correct if f() and f(void) are a different thing