{"version":"https://jsonfeed.org/version/1.1","title":"Shreyash Rai","home_page_url":"https://shreyashrai.com/","feed_url":"https://shreyashrai.com/feed.json","description":"Things I learn and projects I build, a running log of TILs and writeups by Shreyash Rai.","items":[{"id":"https://shreyashrai.com/til/cpp-size-t-underflow/","url":"https://shreyashrai.com/til/cpp-size-t-underflow/","title":"size_t is unsigned, so counting down past zero wraps around","content_html":"<p>I had a loop that walked a vector backwards and it never terminated. The bug is\nthat <code>size_t</code> is <strong>unsigned</strong>, so it can never be negative — subtracting past\nzero wraps to a huge positive number instead.</p>\n<pre><code>// Broken: when i == 0, --i wraps to SIZE_MAX, so i &gt;= 0 is always true.\nfor (size_t i = v.size() - 1; i &gt;= 0; --i) {\n    use(v[i]);\n}\n</code></pre>\n<p>The same trap hides in any <code>v.size() - 1</code> when the vector is empty: <code>0u - 1</code>\nis <code>SIZE_MAX</code>, not <code>-1</code>, so a \"last index\" computed that way points way off the\nend.</p>\n<p>One fix is to offset the index by one and count the <em>other</em> variable down, so\nthe loop variable stays in valid unsigned territory:</p>\n<pre><code>// Fixed: i is the count remaining; the real index is i - 1.\nfor (size_t i = v.size(); i &gt; 0; --i) {\n    use(v[i - 1]);\n}\n</code></pre>\n<p>The general rule: if a value can go negative, don't store it in an unsigned\ntype. Reach for a signed index (or C++20's <code>std::ssize</code>) when you need to count\nbelow zero.</p>\n","date_published":"2026-07-03T00:00:00.000Z","tags":["c++","gotchas"]},{"id":"https://shreyashrai.com/blog/how-this-site-works/","url":"https://shreyashrai.com/blog/how-this-site-works/","title":"How this site works","summary":"A static, Markdown-driven site built with Astro — why it exists and how publishing a new post is just adding a file.","content_html":"<p>This site is a running log of things I learn and the projects I build. The most\nimportant property it has is that publishing is frictionless: writing a new post\nis exactly as much work as creating a Markdown file and pushing to git. No CMS,\nno dashboard, no database.</p>\n<h2>The stack</h2>\n<p>It's built with <a href=\"https://astro.build\">Astro</a> as a fully static site. Every TIL\nand every post is a Markdown file with a little frontmatter block at the top —\na title, a date, some tags. Astro reads those files at build time, validates the\nfrontmatter against a schema, and turns each one into a page. The output is\nplain HTML and CSS with essentially no client-side JavaScript, so pages load\ninstantly and there's nothing to break.</p>\n<p>There are two kinds of writing here:</p>\n<ul>\n<li><strong>TILs</strong> (\"Today I Learned\") — short, dated, tagged notes. This is the heart\nof the site and where most of the activity is.</li>\n<li><strong>Posts</strong> — longer writeups and essays, like this one.</li>\n</ul>\n<h2>Why no JavaScript framework</h2>\n<p>Because the content is the product. A personal site that's mostly text doesn't\nneed a rendering framework shipped to the browser; it needs good typography, a\nreadable column width, and fast loads. Keeping the build static means the whole\nsite is a folder of HTML files that any host can serve, and there's no runtime\nto patch or attack.</p>\n<h2>Following along</h2>\n<p>Everything is available as a feed. There's a\n<a href=\"/rss.xml\">combined feed</a> of TILs and posts, and if you only want one or the\nother, each has its own. Feeds carry the full text, so you can read without ever\nvisiting the site — that's the point of them.</p>\n<p>If you want to see how the sausage is made, the source is on\n<a href=\"https://github.com/ItsMat78\">GitHub</a>.</p>\n","date_published":"2026-07-03T00:00:00.000Z","tags":["meta","astro"]},{"id":"https://shreyashrai.com/links/the-original-link-blog/","url":"https://shreyashrai.com/links/the-original-link-blog/","title":"Simon Willison's link blog — the format worth stealing","content_html":"<p>Kicking off a link blog here, the way <a href=\"https://simonwillison.net/\">Simon Willison</a>\ndoes it: short posts that point at something worth your time with a line on why.\nLess pressure than an essay, and over a year it becomes the most useful thing on\nthe site. This is the first one.</p>\n<p>Link: <a href=\"https://simonwillison.net/\">https://simonwillison.net/</a></p>","date_published":"2026-07-02T00:00:00.000Z","tags":["meta","blogging"]},{"id":"https://shreyashrai.com/quotes/willison-on-writing/","url":"https://shreyashrai.com/quotes/willison-on-writing/","title":"Quote — Simon Willison","content_html":"<p>You should blog about things you've learned, even if you don't think anyone will\nread it. The act of writing it up is what cements your own understanding.</p>\n","date_published":"2026-07-01T00:00:00.000Z","tags":["blogging","meta"]},{"id":"https://shreyashrai.com/links/astro-content-layer/","url":"https://shreyashrai.com/links/astro-content-layer/","title":"Astro's Content Layer API","content_html":"<p>The <code>glob()</code> loader plus Zod schemas are what make every TIL, post, link, and\nquote on this site type-checked at build — a malformed frontmatter block fails\n<code>astro build</code> instead of shipping a broken page. Worth a read if you run any\nkind of content site.</p>\n<p>Link: <a href=\"https://docs.astro.build/en/guides/content-collections/\">https://docs.astro.build/en/guides/content-collections/</a></p>","date_published":"2026-06-28T00:00:00.000Z","tags":["astro","meta"]},{"id":"https://shreyashrai.com/til/linked-lists/","url":"https://shreyashrai.com/til/linked-lists/","title":"Linked Lists","content_html":"<h2>Introduction</h2>\n<ul>\n<li>Array stores data in continuous or contiguous memory.</li>\n<li>All accessible in O(1) time, because it directly reaches address of elements inside by simple arithmetic, BECAUSE they are all stored together.</li>\n<li>But, there's problems with this contiguous memory is that when there's no space for the next element you must copy the elements to a new location, wasting time.</li>\n<li>That's why we use linked lists because it stores it's data in random places of the memory and each are connected.</li>\n</ul>\n<h2>Linked Lists</h2>\n<ul>\n<li>Stores data in Nodes that are spread out in memory but all nodes are storing address of the next node in the list.</li>\n<li>Traversal time complexity: O(n)</li>\n<li>Insertion time complexity: O(n)\n<img src=\"/public/images/Pasted%20image%2020260622201004.png\" alt=\"&quot;Meow&quot;\" /></li>\n</ul>\n<h2>Arrays vs linkedlists</h2>\n<h3>a) Cost of Accessing an element</h3>\n<ul>\n<li>Array needs constant time O(1) because simple arithmetic leads to the next element.</li>\n<li>Address of i th element = Base_address + i * Size_of_data_type</li>\n<li>Linked List needs O(n) where is n is number of elements in the list.</li>\n</ul>\n<h3>B) Memory Requirement</h3>\n<ul>\n<li>\n<p>Array has a fixed size, so partially filled array takes as much space as it was full.</p>\n</li>\n<li>\n<p>So there's a lot of unused space in memory.</p>\n</li>\n<li>\n<p>Sometimes, memory may not be available all the time since contiguous memory so it requires copying of data.</p>\n</li>\n<li>\n<p>Linked List requires extra memory for pointer variables. They are 4 bytes each (in 32bit system). But 8 bytes in 64bit system.</p>\n</li>\n<li>\n<p>But it does not leave unused memory.</p>\n</li>\n<li>\n<p>It's usually better than array when the datatype being stored has higher size. But depends on the case on which performs better.</p>\n</li>\n<li>\n<p>Nodes being stored at random places in memory.</p>\n</li>\n</ul>\n<h3>C) Cost of insertion</h3>\n<ol>\n<li><strong>In the beginning</strong>\n<ul>\n<li>Arrays have to shift all elements by one and then insert the value at starting. So O(n)</li>\n<li>Linked List disconnects head node and reattaches new node in the beginning. So O(1)</li>\n</ul>\n</li>\n<li><strong>In the end</strong>\n<ul>\n<li>Arrays: Just insert element at the new free location, or copy into new array if it is full. So O(1) or O(n)</li>\n<li>Linked List needs to traverse until the end then attach new node. So O(n)</li>\n</ul>\n</li>\n<li><strong>At i-th location (average case)</strong>\n<ul>\n<li>Arrays: Shift some elements forward. So O(n)</li>\n<li>Linked list: Traverse i elements, so O(n)</li>\n</ul>\n</li>\n</ol>\n<h2>Implementation in both C and C++</h2>\n<p><strong>Making a node</strong></p>\n<pre><code>typedef struct Node{\n\tint data;\n\tstruct Node* next;\n} Node;\n</code></pre>\n<pre><code>struct Node{\n\tint data;\n\tNode* next;\n};\n</code></pre>\n<p><strong>Initializing Linked List</strong></p>\n<pre><code>Node* A; //initialising empty LL\nA = NULL; //Setting it as Null initially\nNode* temp = (Node*) malloc(sizeof(struct Node)) //typecasting required, creating a new temporary node\n(*temp).data = 2; //Filling data in node\n(*temp).next = NULL; //Attaching it to null address\nA = temp; //Setting A as temp node\n</code></pre>\n<pre><code>Node* A;\nA = NULL;\nNode* temp = new Node();\ntemp-&gt;data = 2;           // -&gt; is basically short form of the deferencing (*) and accessing structure with .\ntemp-&gt;next = NULL;\nA = temp;\n</code></pre>\n<pre><code>Node* temp1 = A;\nwhile (temp-&gt;next != NULL){\n\ttemp1 - temp1 -&gt; next;\n}\n\ntemp = new Node();\ntemp-&gt;data = 4;\ntemp-&gt;next = NULL;\ntemp1-&gt;next = temp;\n</code></pre>\n<pre><code>#include &lt;stdlib.h&gt;\n#include &lt;stdio.h&gt;\n\ntypedef struct Node {\n\tint data;\n\tstruct Node* next;\n} Node;\n\nvoid Insert(Node** pointerToHead, int x);\nvoid Print(Node* head);\n\nint main(){\n\tstruct Node* head = NULL;\n\tint n,x;\n\tprintf(\"Enter number of nodes: \")\n\tscanf(\"%d\", &amp;n);\n\tfor (int i=0; i &lt; n; i++){\n\t\tprintf(\"Enter a number: \");\n\t\tscanf(\"%d\", &amp;x);\n\t\tInsert(&amp;head, x);\n\t\tPrint(head);\n\t}\n\tprintf(\"\\n\");\n}\n\nvoid Insert(Node** pointerToHead, int x){\n\tNode* temp = (Node*) malloc(sizeof(struct Node));\n\ttemp-&gt;data = x;\n\ttemp-&gt;next = *pointerToHead;\n\t*pointerToHead = temp;\n}\n\nvoid Print(Node* head){\n\twhile (head != NULL){\n\t\tprintf(\"%d \",head-&gt;data);\n\t\thead = head-&gt;next;\n\t}\n\tprintf(\"\\n\");\n}\n</code></pre>\n<p>Notes:</p>\n<ul>\n<li>Node** is a pointer to pointer. Dereferencing it gives us the pointer to a Node. Then we can use -&gt; to grab its data and next</li>\n<li>We used pointer-to-pointer so that we can modify what is at the address of the memory. If we used pointer directly, that would not work because this new argument inside Insert would be a COPY of the pointer and not the one we want to modify.</li>\n<li>Insert function handles both empty and non-empty linked list as if it is empty then head is null which the new temp node takes anyways.</li>\n<li>For C++ we can use classes and the new function (Node* temp = new Node();) for easy.</li>\n<li>This code still doesn't free up memory.</li>\n</ul>\n","date_published":"2026-06-22T00:00:00.000Z","tags":["C++","DSA"]},{"id":"https://shreyashrai.com/quotes/knuth-optimization/","url":"https://shreyashrai.com/quotes/knuth-optimization/","title":"Quote — Donald Knuth","content_html":"<p>Premature optimization is the root of all evil.</p>\n","date_published":"2026-06-20T00:00:00.000Z","tags":["programming"]}]}