Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Lua strings normally are copy on use with interning, and NOT by reference. That makes passing binary data between lua and C a relative nightmare. This library avoids the troubles inherent in using lua strings as buffers, by making a new type that acts like strings, but copies as rarely as possible, is mutable and not interned, and can be passed to lua and back to C without copying twice.

Every time you lua_pushlstring on a buffer you're adding another entry to luajit's internal string lookup table, which eventually makes everything slow down. lua strings should only be used for data that's expected to repeat itself really, like function names, or keywords.

Buffers are for purely binary undecoded data, octet strings so to speak. All decoding and formatting would be in a separate module, leaving this stuff purely about shuffling around data agnostically.

Obviously buffers can't be used in modules that already use strings as buffers... like the io module that's right I'm looking at you core. But it should be relatively simple to adjust those modules, or create new ones, perhaps based on libuv, that use buffers where buffers are called for.

something like this...

local buffer = require("buffer")
local io = require("iobufferderp") -- some third party module that uses buffers
local mod = require("somebufferusingcmodule")
local f = io:open({path="somedest",mode=io.WRITE})
local buf = buffer:new(1024)
while true do
mod:fill(buf)
f:write(buf)
end
f:close()

C code can use buffer.h to create and push around buffers. Buffers are dependent on Lua since they use a context's allocation function so that they won't skirt around any memory management being done to lua by just using the raw malloc. Other than that they're pretty pure C. You can assign to and read from buffers without worrying about the underlying lua at all.

This library is sort of erring on the side of don't copy, and not on the side of caution, so there are some issues with "two" "different" buffers both getting mutated by the same operation. I figure that's more important to do by default, since you can always wrap your buffer slice with a buffer clone, but you can't remove the buffer copy if it's inside the buffer slice to ensure independent buffer slices. It's not a big issue with buffers either, since you generally will be doing all the slicing and examination before the buffer is mutated again. But some people might get confused when they use buffer:slice(...) and what it returns is a memory view not a memory copy.

About

Efficient binary buffer operations.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages