eckzow
Zipline uses drones to deliver critical and lifesaving medicine to thousands of hospitals serving millions of people in multiple countries. Our mission is to provide every human on Earth with instant access to vital medical supplies. Join Zipline and help us make this a reality for billions of people.
We're hiring an embedded systems specialist to help us build perception systems for our aircraft. You'll build high-performance, real-time, safety-critical embedded software systems from kernel drivers to neural networks. We write Rust and C++ on embedded Linux, and we work with hardware from i2c to GPUs. We train networks and analyze data with industry-standard Python tools.
More information and apply @ https://flyzipline.com/careers/job/4633974003/?gh_jid=463397...
We're hiring for many other positions, too! https://flyzipline.com/careers/
> While that could mean just about anything, nearly everyone who writes a half-decent hand-written parser, whether they know it or not, is writing a recursive descent parser [1].
> [1] Parsing Expression Grammars (PEG)s and “parser combinators” in some functional languages are just recursive descent parsers in disguise.
Which, while I haven't thought about it deeply, intuitively makes some sense: parser combinators encourage an approach mostly equivalent to little functions that do something like "parse a $thing, or parse a $different_thing" (etc.) which very much translates down like a recursive descent parser.
Accepts a .hex so you can use whatever toolchain you want.
Also, a significant fraction of embedded code is going to be "unsafe" Rust by definition: drivers performing volatile load/stores on memory mapped hardware. In those scenarios, defect mitigation techniques are a matter of system architecture (MPUs, pre-empting deadline-based task schedulers) rather than being language-specific. Arguably even Rust provides you with no protection against the most devious bugs (memory barrier usage, cache-DMA interactions).
The usual argument is that headers don't actually provide good encapsulation: implementation details internal to the class (i.e. private members) end up getting leaked into the public header. There are workarounds (pimpl, opaque "handle" types, etc.) but they all have their own disadvantages (mostly an extra layer of indirection).
Complicating the matter is the issue of static polymorphism--CRTP and its friends cause the template-ization forcing lots of code into headers. Smarter compilers help a bit (with de-virtualization and constexpr), but if you want to guarantee that something is resolved at compile time, turning it into a template is the only real option.
Lastly there's the inlining specter; the separate compilation model means that without link-time optimization (which has admittedly made great strides in the last few years), code must be moved into headers to be eligible for inlining. Premature optimization and all that, but this is a death-by-a-thousand-cuts situation where the language gets in the way of doing the performant thing (and you're probably only using C++ if you care about performance in one aspect or another).
None of these things is an insurmountable problem, to be sure, but they represent little inefficiencies (either for the programmer or the program) which are not generally present in more modern language implementations. I am thinking primarily of Rust, for which the static polymorphism and link time optimization stories are strong--although perhaps that is in direct reaction to some of these C++ shortcomings, and we'll discover Rust has warts of its own after a few decades of wear and tear.
Although, there's certainly nothing magical that prevents the optimizer from generating such code. Here's something[1] I just threw together that (ab)uses constexpr to do just that.
On my machine, building with:
$ clang++ -std=c++14 fizzbuzz.cpp -O2 -S
Gives code similar to: main: # @main
.cfi_startproc
# BB#0:
pushq %rax
.Ltmp0:
.cfi_def_cfa_offset 16
movl $1, %edi
movl $_ZL6output, %esi
movl $413, %edx # imm = 0x19D
callq write
xorl %eax, %eax
popq %rdx
retq
.Ltmp1:
.size main, .Ltmp1-main
.cfi_endproc
.type _ZL6output,@object # @_ZL6output
.section .rodata,"a",@progbits
_ZL6output:
.ascii "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz\n"
Of course, having now written this I feel like I should retroactively fail my last interview.In such a discussion we might talk about whether it makes sense to make the /15 case "fall out" naturally. Using your example, there's an implicit assumption that the requirements would change to {4: fizz, 5: buzz, 20: fizzbuzz}, but in real life I've found things have the annoying tendency to change to, e.g. {4: fizz, 5: buzz, 15: fizzbuzz}.
[1] http://www.winningwordsproject.com/assets/pages/340/producti...
The technique is useful to a point. I used a similar technique for a project and the inability to use locals threw off new hires (who usually created a bug before understanding why).
The bigger problem than educating new users though was that as the number of threads scales up (or grows in hierarchy) you burn more and more CPU time stacking/unstacking your calls just to get to the check that "whoops, this thread should still have been blocked." Between that and implementing preemption, at some point you just have to buckle down and pay for stacks.
:s/t:50/t:60/g
More serious response: I think after many years of training ones brain to use the features available to it some of those features become second nature and subconscious. This is great for editing and it's the reason I immediately saw that you left me a really easy way to do it, but it can make seeing the value of new features more difficult.
It's also true that ARM has heard some of these complaints, which is why there were steps toward standardizing some things--like, the SYSTICK interface--in v7-M. It's really been a step up since the ARM7TDMI, and I hope that it will continue with v8-M or whatever the next revision ends up being.
Personally, when I'm dealing with a discrete chip and I need to reset it I've found that the most reliable methods that don't set off the hack-o-meter too badly are to wait for or directly invoke watchdog hardware... but yes, that's essentially always device specific.
But since I'm a Cortex M fanboy I have to defend its reset capabilities :)
For your specific case, try something like
volatile uint32_t *AIRCR = (volatile uint32_t*)0xE000ED0C;
const uint32_t VECTKEY = 0x05FA << 16;
const uint32_t SYSRESETREQ = 1 << 2;
void take_reset()
{
*AIRCR = VECTKEY | SYSRESETREQ;
__dsb();
while(1);
}
It's technically dependent on external hardware in your processor subsystem, but it should work if your implementer has half a brain (or, at least cares enough to read the integration manual). If it doesn't work, please flog your implementer publicly so that I can know to avoid them in the future...Incidentally, even that tiny code snippet is uses a C extension (the __dsb intrinsic) which is either a great example of how C can be wielded to great power (I can generate raw instructions!) or how C is terribly handicapped (I need a special compiler extension or all my system code is horribly broken!). All depends on point of view, I guess...
Anyway, more info @ page 498, http://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readi...
The specific details require you to dig a bit past explaining just the immediate encoding, but in the clearing case there's a dedicated instruction for clearing the bit specified by the immediate:
BIC - Bit Clear (immediate) performs a bitwise AND
of a register value and the complement of an immediate
value, and writes the result to the destination register.
As I mentioned in my other post, zero-rotation encodings are gamed out as well (to allow byte repetition).For those interested, check out page 122 of the ARMv7-M architecture reference manual[2]:
// ThumbExpandImm_C()
// ==================
(bits(32), bit) ThumbExpandImm_C(bits(12) imm12, bit carry_in)
if imm12<11:10> == ’00’ then
case imm12<9:8> of
when ’00’
imm32 = ZeroExtend(imm12<7:0>, 32);
when ’01’
if imm12<7:0> == ’00000000’ then UNPREDICTABLE;
imm32 = ’00000000’ : imm12<7:0> : ’00000000’ : imm12<7:0>;
when ’10’
if imm12<7:0> == ’00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : ’00000000’ : imm12<7:0> : ’00000000’;
when ’11’
if imm12<7:0> == ’00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : imm12<7:0> : imm12<7:0> : imm12<7:0>;
carry_out = carry_in;
else
unrotated_value = ZeroExtend(’1’:imm12<6:0>, 32);
(imm32, carry_out) = ROR_C(unrotated_value, UInt(imm12<11:7>));
return (imm32, carry_out)
[1] http://graphics.stanford.edu/~seander/bithacks.html (worth a read on its own if you're into this kind of thing)[2] http://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readi... (no-registration link)
One great story for why this way might be better is that with a small tweak (to allow dynamic [de]registration of command functions) it is much more open to extension.
To continue using the somewhat creaky "text game" example, if possessing certain items or being in a particular room affects the available command set, this can be easily included: without a magic feather, "fly" returns "You don't know how to do that" but when you pick up said feather a new action is registered, and now "fly" works properly.
Now, I'm not sure I'd implement this particular game that way, but such an interface tends to be useful for building plugin systems, etc.
It's mainly for this reason that large switch statements, particularly those not doing "math" of some sort, tend to be a code smell.[1]
>>> a = {'a':1,'b':2}
>>> b = {'b':3,'c':4}
>>> def keylist(*maps):
... return ', '.join(sorted({str(k) for m in maps for k in m.keys()})) or '<none>'
...
>>> keylist(a, b)
'a, b, c'
>>> keylist()
'<none>'
I'm sure people will have differing opinions on the readability of a nested set comprehension, but from the bullets at the top of the article to one-liner implementation in ~30 seconds. (For an arbitrary number of maps, no less.)(edit: added '<none>' on empty, fixed formatting, whoops now I'm over 30 seconds :))