Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Ihmemies
Oct 6, 2012

We had to implement a binary search algorithm, which searches for the first missing number from an ordered list. It actually seems to work..

code:
7, 8, 9, 10, 11, 12, 13, 17, 18, 20, 231804209, 22721, -1827832832, 631, -1827857616, 631, -1826868432, 631, -1826868000, 631, 8, 0, 939524152, 22721, -1827832832, 631, -1827857616, 631, -1826869968, 631, 0, 0, 86, 631, 100663302, 22721, -1827857376, 631, -1827857520, 631, -1826867232, 631, -1827833696, 631, 132, 1702122272, 50331651, 22721, -1827857520, 631
l: 0     r: 9999  m: 4999  width: 9999 
l: 0     r: 4999  m: 2499  width: 4999 
l: 0     r: 2499  m: 1249  width: 2499 
l: 0     r: 1249  m: 624   width: 1249 
l: 0     r: 624   m: 312   width: 624 
l: 0     r: 312   m: 156   width: 312 
l: 0     r: 156   m: 78    width: 156 
l: 0     r: 78    m: 39    width: 78   
l: 0     r: 39    m: 19    width: 39   
l: 0     r: 19    m: 9     width: 19   
l: 0     r: 9     m: 4     width: 9   
l: 4     r: 9     m: 6     width: 5   
missing found: l: 6 r: 9
14missing!
Don't ask me why the numbers in a list print out like that, I have no idea.

C++ code:
/**
 * @brief searchSmallestMissing searches for the smallest missing integer in a sorted array of integers.
 * The function works by recursively dividing the search range until it finds the missing value or determines
 * there isn't one. It uses a binary search approach where the middle element is compared to its index
 * to decide whether to continue the search on the left or the right half of the current search range.
 * This comment was generated by ChatGPT.
 *
 * @param fromArray Pointer to the array to be searched.
 * @param left The starting index of the current search range.
 * @param right The ending index of the current search range.
 * @return The smallest missing integer or NO_VALUE_MISSING if no value is missing.
 */
int searchSmallestMissing(int* fromArray, int left, int right) {
    // Compare left with the next value
    if(left < right && fromArray[left + 1] != fromArray[left] + 1) {
        printf("missing found: l: %d r: %d\n", left, right);
        return fromArray[left] + 1;
    }

    // If we are at the end of the search, realize no value is missing
    if(left == right-1) {
        return NO_VALUE_MISSING;
    }

    int mid = left + (right - left) / 2;

    printf("l: %-5d r: %-5d m: %-5d width: %-5d\n", left, right, mid, right-left);

    // Decide if we go search from left or right side of mid
    if (fromArray[mid] - fromArray[0] != mid) {
        return searchSmallestMissing(fromArray, left, mid);
    }

    return searchSmallestMissing(fromArray, mid, right);
}
Does that make sense? It had to be implemented recursively, and I saw examining the next index from left as the only option for base case. It took me many hours to get it working. Finally I realized I can actually use printf to "see" what it does instead of just using the debugger.

Adbot
ADBOT LOVES YOU

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

quote:

Don't ask me why the numbers in a list print out like that, I have no idea.

Only the first ten elements look valid to me; Looks like either you're either operating on a list of length 50 that you are not initializing past element 10, or, you are operating on a list of length 10 but the function thinks it's of length 50 so you're seeing unrelated/garbage values past the end of the array.

edit: glancing at your code a bit more, I think you want your base case (the "do I have the empty range of values to search" to come first; otherwise, I don't think you'll get the right answer when, say, the input list is of length 1).

Dijkstracula fucked around with this message at 20:10 on Sep 25, 2023

Ihmemies
Oct 6, 2012

Dijkstracula posted:

Only the first ten elements look valid to me; Looks like either you're either operating on a list of length 50 that you are not initializing past element 10, or, you are operating on a list of length 10 but the function thinks it's of length 50 so you're seeing unrelated/garbage values past the end of the array.

The test functions for algorithms were provided by school, but they are quite obtuse and have no comments at all. The test functions apparently generate n sized lists with a random generator. Lists can be 10, 100 or 1000 long and the tester prints up to first 50 numbers. I was happy enough when my binary search function passed the tests.

The code which school has provided to students in various courses has quite often been something that I would not write or distribute. It’s rarely pleasant to read, but I guess they have their reasons.

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

I've got Opinions on your instructor's decisions there, but I also had Opinions on your other class's instructor's decisions, so I guess at least there's consistency :v:

Beef
Jul 26, 2004
The numbers after 20 look like they are uninitialized values. You need to pass the correct length to the function that is printing the array.

The task itself is super weird and artificial. I guess that the trick is that you want to keep descending left as long as it's not "full"? That's the vital information you should mention in the last comment.

Your function was a more confusing that it should for me because I expected a binary search to be more in the following canonical form:

code:
binsearch(range)
if (range.right - range.left > 1)
  binsearch(go_left ? left : right)
else 
  return something;
Functionally, your solution only works for certain examples. Try finding a proper left/right conditional, implementing the trick I mentioned above.


At the risk of solving someone's homework:

hint 1: Your code only works if you keep descending to the left until the last step. If there is a right followed by left it will not find the right result.

hint 2: You keep looking at arr[0], don't

solution: Your left/right condition should be something like `arr[right] - arr[left] == right - left` if I am not mistaken.


edit: Am I an idiot? I think this might work because you need the first non-consecutive.
edit 2: try running an example that has the missing element in the second half of the list

Beef fucked around with this message at 21:49 on Sep 25, 2023

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Beef posted:

edit: Am I an idiot? I think this might work because you need the first non-consecutive.
At the very least I think you're right in that the conditional should be something like `fromArray[mid] - fromArray[left] != mid`

When I'm stuck writing artificial things like this I like doing the Jon Bentley thing and manually writing out things that have to be true at each step of the computation (which, because you're doing thing recursively, is at the start of each function call), something like

code:
int missing(int *a, int left, int right) {
  // invariant: missing element, if it exists, is contained in range [left, right) (that 
  // is, the interval from `left` up to but not including `right`)

  ...
}
Making stuff like this explicit to myself makes it easier to visualize what my base cases should be: what happens if that range is empty? What if it contains one element? What if it contains two elements? Aha, now what are the cases for if those two elements have a missing element between them or not? And so on...

Dijkstracula fucked around with this message at 20:39 on Sep 25, 2023

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Dijkstracula posted:

I've got Opinions on your instructor's decisions there, but I also had Opinions on your other class's instructor's decisions, so I guess at least there's consistency :v:
I first thought "what the heck, you're looking for a leftmost thing, so if you're binary searching and you find a 'missing' you're still gonna have to look at everything further left to make sure none of those are also a 'missing' so what's the benefit?"

Then I thought it was comparing *two* sorted lists, where one has had one item removed, and looking for what the removed item is, which would be a valid use for a binary search provided duplicate entries are not allowed (because everything to the right of target a[i]!=b[i], and everything to the left a[i]==b[i]).

Then I saw that was not the case and I thought for a moment "oh but if you find a missing at 50% and look left and find another at 25% then you don't have to look at the ones in between so there is a saving after all".

Then I realized that no, you still have to look at the 25% to the left (if there's no others missing in there), and if you just did a linear scan from the left you'd look at those and then stop at the first so it would be shorter by one lookup in this case, and there is no case where the binary search reads fewer items than the linear search from left for this algorithm, jesus, is this instructor *intentionally* making nonsense problems, is his entire course like a piece of performance art commenting on blockchain and AI?

Xerophyte
Mar 17, 2008

This space intentionally left blank

Ihmemies posted:

Does that make sense? It had to be implemented recursively, and I saw examining the next index from left as the only option for base case. It took me many hours to get it working. Finally I realized I can actually use printf to "see" what it does instead of just using the debugger.

I haven't done a particularly deep read but far as I can tell there's nothing horribly wrong with what you've done, it should divide and conquer well enough. I think the termination condition might possibly not be what your professor is looking for but it's not wrong, although you should probably be aware of what you could do instead. Notes in general:
- There's an additional precondition that you're not mentioning, which is that it's necessary that the sorted array contains no duplicates. I'm guessing this is stated as part of the assignment since I don't see how you could solve it with a binary search otherwise, just noting it.
- You shouldn't need to check if there's a missing element within the current range on every iteration, since you already verified that there is when you selected which half of the array to recurse through. You can test if a missing value exists once on the initial call and then either return NO_VALUE_MISSING immediately or proceed with the binary search assuming that when you terminate there will be a missing value.
- You can indeed find a different termination condition. It's possible to write the search in such a way that you terminate when the range is empty, and then return fromArray[left] + 1 which will be guaranteed to be the smallest missing value. Recursing until the range is empty is arguably more "canonical" and in line with how binary searches usually work. You would lose the potential early exit. Which is "better" depends on other things like what sort of input you'd expect to get, if the loop code is more/less efficient with better/worse branch behavior, etc. It's a toy example so there's no real world data to provide a real world answer.

roomforthetuna posted:

Then I realized that no, you still have to look at the 25% to the left (if there's no others missing in there), and if you just did a linear scan from the left you'd look at those and then stop at the first so it would be shorter by one lookup in this case, and there is no case where the binary search reads fewer items than the linear search from left for this algorithm, jesus, is this instructor *intentionally* making nonsense problems, is his entire course like a piece of performance art commenting on blockchain and AI?

Nah, binary search works fine here. The proposed algorithm effectively splits the array into two half-sized subarrays, tests (in constant time) if there's a missing number in the left sublist, and only visits the right sublist if there is no missing number on the left. Problem size is halved at each step so the time complexity is reduced from linear to logarithmic as usual. In that sense it's a perfectly okay -- if very artificial -- teaching problem. You have to assume that the list contains no duplicates as a precondition in addition to the listed stuff but, fine, it's a toy problem.

Xerophyte fucked around with this message at 00:20 on Sep 26, 2023

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Xerophyte posted:

Nah, binary search works fine here. The proposed algorithm effectively splits the array into two half-sized subarrays, tests (in constant time) if there's a missing number in the left sublist,
Oh, I see, it tests in constant time because len(array) == diff(first, last) if there's no gaps (or duplicates). Yeah, that's not *so* awful then.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Dijkstracula posted:

When I'm stuck writing artificial things like this I like doing the Jon Bentley thing and manually writing out things that have to be true at each step of the computation

enough with the Dafny evangelism

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Subjunctive posted:

enough with the Dafny evangelism

:hehe:

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ihmemies posted:

We had to implement a binary search algorithm, which searches for the first missing number from an ordered list.

Just FYI, this isn’t binary search. Binary search is a specific divide-and-conquer algorithm for trying to find a given value in a sorted array. The algorithm in your assignment is a divide-and-conquer algorithm, and we could hand-wavily describe it as a kind of search, and it involves a sorted array, but it’s not “binary search”.

It’s like “record player”. If you think about the term from first principles, it could mean all kinds of devices, but in reality it means a specific thing.

Just another way your teacher is being weirdly confusing.

Ihmemies
Oct 6, 2012

Whole task was:

code:
Function searchSmallestMissing()
Let us consider another similar problem. The algorithm searchSmallestMissing() takes
 an array of unique integer numbers in ascending order as a parameter. From the array,
 the algorithm should find the smallest missing number For example, with input of
 [0, 1, 2, 3, 4, 5, 12, 23], searchSmallestMissing() returns 6. If all numbers are in sequence,
 thus no number is missing, the function must return NO_VALUE_MISSING.
int searchSmallestMissing(int* A, int left, int right):

int left, the leftmost index of an array, initially 0

int right, the rightmost index of an array, initially size-1

int searchSmallestMissing(int* A, int left, int right){
  // returns the first missing number, or NO_VALUE_MISSING if not found
  return NO_VALUE_MISSING;
}
Write searchSmallestMissing() as a c++ function that uses divide-and-conquer and is
 implemented as recursion.
Edit the snippet with the editor of your choice.

rjmccall posted:

Just FYI, this isn’t binary search. Binary search is a specific divide-and-conquer algorithm for trying to find a given value in a sorted array. The algorithm in your assignment is a divide-and-conquer algorithm, and we could hand-wavily describe it as a kind of search, and it involves a sorted array, but it’s not “binary search”.

It’s like “record player”. If you think about the term from first principles, it could mean all kinds of devices, but in reality it means a specific thing.

Just another way your teacher is being weirdly confusing.

It is probably me being confusing. We had to develop a function which used decrease divide and conquer principles, so I kind of understood he wanted us to use something like binary search. By which I mean halving the search area in every iteration, instead of iterating through the whole list one index at a time.


Beef posted:



Functionally, your solution only works for certain examples. Try finding a proper left/right conditional, implementing the trick I mentioned above.


At the risk of solving someone's homework:

hint 1: Your code only works if you keep descending to the left until the last step. If there is a right followed by left it will not find the right result.

hint 2: You keep looking at arr[0], don't

solution: Your left/right condition should be something like `arr[right] - arr[left] == right - left` if I am not mistaken.


edit: Am I an idiot? I think this might work because you need the first non-consecutive.
edit 2: try running an example that has the missing element in the second half of the list

Thanks. The deadline for homework was on last Sunday, so I asked only after the deadline for returning the homework was passed.

We were provided a Qt project in a zip file with some premade test functions. So we had to only implement the specific functions with iteration, then with recursion. The tester did the rest. I did not really understand why it started printing weird numbers like 19, 406632848, 165920, 749745312, 540, I just assumed it does what it's supposed to do.

I guess I will have to look at the tester code in more detail, and try to understand what it does, and try to coax it to put the missing numbers to any possible place, not just inside the first 10 numbers or so.

Maybe after that I'd better understand the faults in my solution, when the tester tests it with more cases.

Ihmemies fucked around with this message at 10:59 on Sep 29, 2023

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Okay, yeah, the assignment is using the terms correctly.

The right way to approach problems like this is to step back from the code for a second and think about what you know at each step of the algorithm. (The fancy way to say this is that you’re defining your invariants.)

In this case, we know these things from the problem statement:
  • The array is sorted.
  • The elements of the array are unique.

Since we never modify the array, these things stay true the entire time.

We want to find the first element that is not the previous element + 1. If you look at a few examples, you’ll see that there’s another way of thinking about this: there’s a prefix of the array where each element increases by 1, and you want to find the end of it. The first element is always part of that prefix (unless the array is empty), but we don’t know anything about the rest of the array, and if the prefix runs all the way to the last element, there are no missing elements. As we recurse, we’ll be looking at smaller and smaller slices of the array, but if we generalize those three things, they seem like useful things to keep knowing:
  • arr[start] is in the prefix
  • we don’t know whether arr[start+1] is in the prefix
  • if arr[end] is in the prefix, there are no missing elements

If we can keep those three invariants, then whenever we complete the recursion, we’ll have the final answer. This is a really nice property — it means that when we recurse, we can always immediately return the answer we get. (That also means we could do this without recursion if we were allowed to.)

There’s one last property we want to make sure we keep when we recurse. We do need to make sure we’re always looking at a smaller problem, or else the recursion might be infinite. So whenever we make a recursive call, we want to know that the new (end - start) is smaller than the current (end - start). This isn’t strictly speaking an invariant, but it’s a rule that’s going to guarantee we make progress.

Now we can think about the code and think about how we can make the problem smaller at each step while still maintaining these invariants and making progress.

Finding the first element that isn’t the previous element + 1 is normally the sort of condition that would require a linear search through the array. But the guarantees of sorting and uniqueness give us a shortcut, because now we can test if the prefix extends to some element by just testing if the difference between the indexes matches the difference between the values. The exact relationship is super important, and it’s really easy to get it “off by one”, so I suggest writing out an example array on paper or something, with the indexes next to the elements, and making sure your formula works.

Then the basic structure of your solution is essentially:

1. Figure out how long the slice of the array is.
2. Deal with the base cases (lengths <= 1).
3. Otherwise, find an index halfway through the array.
4. Check if that’s still part of the prefix.
5. Recurse, making sure you maintain all the invariants above with the new information you just got, and making sure that the new array is smaller.

rjmccall fucked around with this message at 18:11 on Sep 29, 2023

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I kind of suck at compilation units and hoped somebody could explain why testing for a header guard elsewhere sometimes doesn't work. Like, let's say:

code:
#ifndef __BUTT_H__
#define __BUTT_H__

#define BUTT_FOO 1

...

#endif // __BUTT_H__
And then in face.c:
code:
#include "butt.h"

#ifdef __BUTT_H__
// In this simple example, it would actually work
#endif
...
However, I've had (multiple) situations where it didn't and I had to, say, test for BUTT_FOO instead.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

I think it’s going to be hard to answer that without an example, but this thread is full of wizards

chglcu
May 17, 2007

I'm so bored with the USA.
Are you sure you’re using #ifdef when it fails and not just #if? #if __BUTT_H__ would evaluate to 0.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

chglcu posted:

Are you sure you’re using #ifdef when it fails and not just #if? #if __BUTT_H__ would evaluate to 0.

Ehh this is the kind of thing I do and I thought I even triple verified it, but you make me so anxious so I'll have to just look again at it.

Edit: I gave up and logged in to mess around and very much if an #ifndef (in this situation) and it puked. I think the problem in this particular case is that the header in file was creating originally with some of the stuff missing and I can still bump into that in one of the permutations. So maybe I'll come back in six months when I do this again and find out what I screwed up that time. ;)

Rocko Bonaparte fucked around with this message at 01:47 on Oct 3, 2023

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Usually when I see something unintuitive when I’m not following the standard pattern, it’s because the headers are cyclically including each other.

Xerophyte
Mar 17, 2008

This space intentionally left blank

Rocko Bonaparte posted:

I kind of suck at compilation units and hoped somebody could explain why testing for a header guard elsewhere sometimes doesn't work. Like, let's say:

[...]

However, I've had (multiple) situations where it didn't and I had to, say, test for BUTT_FOO instead.

This is unlikely to be the reason, but: technically this program is ill-formed since you're not allowed to use guards of the form __BUTT_H__. Identifiers that...
  • have a double underscore anywhere
  • begin with an underscore followed by an uppercase letter
  • are in the global namespace and begin with an underscore
...are reserved for the standard library.

Violation of that particular rule is endemic and if your actual guard identifier is reasonably unique it will likely not be a problem. If your guard is closer to #ifdef __VECTOR_H__ then something exploding is more plausible.

Beef
Jul 26, 2004
Use "#pragma once" y'all

Qwertycoatl
Dec 31, 2008

Xerophyte posted:

This is unlikely to be the reason, but: technically this program is ill-formed since you're not allowed to use guards of the form __BUTT_H__. Identifiers that...
  • have a double underscore anywhere
  • begin with an underscore followed by an uppercase letter
  • are in the global namespace and begin with an underscore
...are reserved for the standard library.

Violation of that particular rule is endemic and if your actual guard identifier is reasonably unique it will likely not be a problem. If your guard is closer to #ifdef __VECTOR_H__ then something exploding is more plausible.

You can also do it to yourself without reserved indentifiers when two of your header files use UTIL_H

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Beef posted:

Use "#pragma once" y'all

I'm not sure if #pragma once works with some of my headers. They're using the trick of requiring an implementation define in one location to allow implementation in the header. Mostly use that for generated headers holding const arrays (serialized image data, etc)

I can't use that pragma elsewhere because not all of my compilers support it. I do use it sometimes in headers for platform code on platforms that support it, but I don't have a lot of platform code that doesn't have shared headers.

Nalin
Sep 29, 2007

Hair Elf
You are actually using a compiler that doesn't support #pragma once? Is it an ancient version of a compiler?

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Nalin posted:

You are actually using a compiler that doesn't support #pragma once? Is it an ancient version of a compiler?

Yes, compilers I'm actively using (lsic86ww) and compilers I'm attempting to use but am having issues with (toshiba TC900). I don't think the fork of turbo c I could use instead of lsic supports it either, but that only runs on 16 bit dos; I have a 32 bit version of lsic, which is quite nice comparatively. I think turbo c's code generation might be better though..

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Xerophyte posted:

This is unlikely to be the reason, but: technically this program is ill-formed since you're not allowed to use guards of the form __BUTT_H__.

What if it's Linux kernel crap? They got their own stuff going on so I dunno if they are playing by their own game there.

Xerophyte
Mar 17, 2008

This space intentionally left blank
The other problem with #pragma once is that if your build includes multiple copies of a file -- not uncommon even in sane scenarios, like when using multiple libraries that share the same public header-only dependency that they expose as part of their API and similar -- then pragma once may happily include both copies and possibly explode your build with multiply defined symbols. This said I still use it liberally in all my hobby projects. I avoid it in the public headers of libraries.

When I write include guards my identifiers are generally on the form PROJECTNAME_DIRECTORY_SUBDIRECTORY_FILENAME_H_. This is annoyingly verbose, but compliant and at least very unlikely to ever conflict. I too have seen #ifdef UTIL_H_, and shuddered in fear.

Rocko Bonaparte posted:

What if it's Linux kernel crap?

My linux kernel knowledge is nonexistant so, uh, I'unno.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Yeah, for private headers - either part of an application, or headers in a library that aren't exposed - if #pragma once doesn't work you're doing something stupid and should just stop doing that. Public headers for a library should make a reasonable effort to work even if things are a bit weird, though, and header guards aren't actually very much work.

Sweeper
Nov 29, 2007
The Joe Buck of Posting
Dinosaur Gum

Xerophyte posted:

The other problem with #pragma once is that if your build includes multiple copies of a file -- not uncommon even in sane scenarios, like when using multiple libraries that share the same public header-only dependency that they expose as part of their API and similar -- then pragma once may happily include both copies and possibly explode your build with multiply defined symbols. This said I still use it liberally in all my hobby projects. I avoid it in the public headers of libraries.

When I write include guards my identifiers are generally on the form PROJECTNAME_DIRECTORY_SUBDIRECTORY_FILENAME_H_. This is annoyingly verbose, but compliant and at least very unlikely to ever conflict. I too have seen #ifdef UTIL_H_, and shuddered in fear.

My linux kernel knowledge is nonexistant so, uh, I'unno.

Why even use a real name, just generate a random string and grep for it in your code lol

Private Speech
Mar 30, 2011

I HAVE EVEN MORE WORTHLESS BEANIE BABIES IN MY COLLECTION THAN I HAVE WORTHLESS POSTS IN THE BEANIE BABY THREAD YET I STILL HAVE THE TEMERITY TO CRITICIZE OTHERS' COLLECTIONS

IF YOU SEE ME TALKING ABOUT BEANIE BABIES, PLEASE TELL ME TO

EAT. SHIT.


Plorkyeran posted:

Yeah, for private headers - either part of an application, or headers in a library that aren't exposed - if #pragma once doesn't work you're doing something stupid and should just stop doing that. Public headers for a library should make a reasonable effort to work even if things are a bit weird, though, and header guards aren't actually very much work.

I've run into those niche cases multiple times in large corporate software (the sort of places to have tens or hundreds of people dedicated to maintaining your build pipelines), but aside from that it's not too much of an issue to switch if needed anyway. Just worth keeping in mind there are cases where it will break something that works with include guards.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

Sweeper posted:

Why even use a real name, just generate a random string and grep for it in your code lol

I used to have an Emacs macro generating header guards from UUIDs. (Nowadays it just uses #pragma once.)

Beef
Jul 26, 2004

Zopotantor posted:

I used to have an Emacs macro generating header guards from UUIDs. (Nowadays it just uses #pragma once.)

There is some delicious irony in using (gensym) to create a unique preprocessor variable name for a header include guard.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I'd like some general way to return values asynchronously in C++. Currently we either park a thread or, occasionally, take a callback when e.g. making an HTTP request. But I'd prefer to return something rather than nest callbacks endlessly. Something like a Future type. Is there anything like that built into the standard library? Should I consider coroutines? Is there a focused lil library that everyone uses?

This is recent-ish clang (Android NDK and iOS SDK) and we're on C++20 (I could probably bump that if necessary).

Absurd Alhazred
Mar 27, 2010

by Athanatos
std::promise has been around since C++11, might be worth looking into?

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


std::future is probably what you want.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
Alternatively, embrace coroutines.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I got the impression that std::future and std::promise block threads, which I was hoping to avoid. Is there some other way to use them like "when this future's done, run this code"?

Coroutines look like what I want, just complicated. I'll give them a shot.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I think the main motivation for a promise is to have something run after something else finishes and has a value to spit out, but I have never used them in C++. It's kind of strange here! I figure you'd pass a function to the promise and "chain" it.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Futures represent values that may not be present yet. You don’t “dereference” them until you need to use the value, in which case you want to block until it’s present because you need the value to proceed.

It sounds like what you want is just a background thread, maybe, that blocks on a thing and then operates on the result. When you say “return asynchronously”, what value is being returned, and what is consuming it?

Adbot
ADBOT LOVES YOU

Nalin
Sep 29, 2007

Hair Elf

Subjunctive posted:

Futures represent values that may not be present yet. You don’t “dereference” them until you need to use the value, in which case you want to block until it’s present because you need the value to proceed.

It sounds like what you want is just a background thread, maybe, that blocks on a thing and then operates on the result. When you say “return asynchronously”, what value is being returned, and what is consuming it?

Sounds like they want something like a JavaScript Promise, where they can include a chunk of code that gets executed when the promise completes. So, yeah, a background thread that blocks on the future and executes some code.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply