feat(cccl): integrate missing CCCL directories — python/, ci/, .agent/, docs/, test/
Sparse-checkout from NVIDIA/cccl main branch to complete cccl_upstream: Added: - python/cuda_cccl/ (226 files) — Python bindings for device-level algorithms Critical for muh toolchain: cuda.compute.reduce_into, scan, radix_sort, etc. Includes 204 .py files with full test coverage for all 27 algorithms - ci/ (163 files) — Build/test infrastructure build_cub.sh, test_cub.sh, build_and_test_targets.sh, matrix.yaml Directly maps to our [INFRA-CI] and [INFRA-BUILD] items - .agent/skills/ (7 files) — NVIDIA's own agent skills for CCCL cccl-style/SKILL.md, cccl-test/SKILL.md, sass-diff/SKILL.md - docs/ (491 files) — Official CCCL documentation CI references, CMake guides, Python compute docs, libcudacxx PTX docs - test/ (12 files) — Top-level integration tests (cuda_smoke, stdpar) - Root configs: .clang-format, .clang-tidy, CONTRIBUTING.md, pyproject.toml - CLAUDE.md symlink → AGENTS.md (NVIDIA's standard) cccl_upstream now mirrors full NVIDIA/cccl structure: Before: 42M (cub + thrust + libcudacxx + cudax + c + examples + benchmarks) After: 53M (+python +ci +docs +.agent +test +configs) This completes the CCCL base needed for: - [muh-bench] items: ci/util/build_and_test_targets.sh for targeted builds - [CCCL-verify] items: python/cuda_cccl/tests/ as reference implementations - [CCCL-test] items: ci/test_cub.sh, ci/test_thrust.sh - Agent workflow: .agent/skills/ for consistent style and test patterns
This commit is contained in:
265
cccl_upstream/docs/_static/search_postprocess.js
vendored
Normal file
265
cccl_upstream/docs/_static/search_postprocess.js
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
const maxBreadcrumbResults = 10;
|
||||
|
||||
const decodeEntities = (value) =>
|
||||
String(value || "")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'|'/g, "'")
|
||||
.replace(/ /g, " ")
|
||||
.replace(/…/g, "...");
|
||||
|
||||
const getDocLinkSuffix = () =>
|
||||
(typeof DOCUMENTATION_OPTIONS !== "undefined" &&
|
||||
DOCUMENTATION_OPTIONS.LINK_SUFFIX) ||
|
||||
".html";
|
||||
|
||||
const pageInfoCache = new Map();
|
||||
|
||||
const getDocTitle = (docName) => {
|
||||
if (
|
||||
typeof Search === "undefined" ||
|
||||
!Search._index ||
|
||||
!Array.isArray(Search._index.docnames) ||
|
||||
!Array.isArray(Search._index.titles)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const index = Search._index.docnames.indexOf(docName);
|
||||
return index >= 0 ? Search._index.titles[index] : null;
|
||||
};
|
||||
|
||||
const getResultDocNameFromHref = (href) => {
|
||||
if (!href) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const withoutAnchor = String(href).split("#", 1)[0];
|
||||
const linkSuffix = getDocLinkSuffix();
|
||||
const suffixIndex = withoutAnchor.lastIndexOf(linkSuffix);
|
||||
if (suffixIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let docName = withoutAnchor.slice(0, suffixIndex);
|
||||
if (docName.startsWith("./")) {
|
||||
docName = docName.slice(2);
|
||||
}
|
||||
|
||||
const contentRoot =
|
||||
document?.documentElement?.dataset?.content_root || "";
|
||||
if (contentRoot && docName.startsWith(contentRoot)) {
|
||||
docName = docName.slice(contentRoot.length);
|
||||
}
|
||||
|
||||
return docName.replace(/^\/+/, "");
|
||||
};
|
||||
|
||||
const getPageInfo = async (docName) => {
|
||||
if (pageInfoCache.has(docName)) {
|
||||
return pageInfoCache.get(docName);
|
||||
}
|
||||
|
||||
const infoPromise = (async () => {
|
||||
const pageUrl = `${docName}${getDocLinkSuffix()}`;
|
||||
const response = await fetch(pageUrl);
|
||||
const html = await response.text();
|
||||
const parsed = new DOMParser().parseFromString(html, "text/html");
|
||||
|
||||
const pageHeading = parsed.querySelector("h1");
|
||||
const breadcrumbLinks = Array.from(
|
||||
parsed.querySelectorAll(".breadcrumb-item a.nav-link"),
|
||||
);
|
||||
const breadcrumbs = breadcrumbLinks
|
||||
.map((breadcrumbLink) => {
|
||||
const rawHref = breadcrumbLink.getAttribute("href");
|
||||
if (!rawHref) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
href: new URL(rawHref, response.url).href,
|
||||
title: breadcrumbLink.textContent?.trim() || null,
|
||||
};
|
||||
})
|
||||
.filter((breadcrumb) => breadcrumb && breadcrumb.title);
|
||||
|
||||
return {
|
||||
pageTitle:
|
||||
pageHeading?.textContent?.replace(/#\s*$/, "").trim() ||
|
||||
getDocTitle(docName) ||
|
||||
null,
|
||||
breadcrumbs,
|
||||
};
|
||||
})().catch(() => null);
|
||||
|
||||
pageInfoCache.set(docName, infoPromise);
|
||||
return infoPromise;
|
||||
};
|
||||
|
||||
const addBreadcrumbTrail = async (listItem) => {
|
||||
if (
|
||||
!listItem ||
|
||||
listItem.dataset.ccclBreadcrumbsAttached === "true" ||
|
||||
listItem.dataset.ccclBreadcrumbsPending === "true"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
listItem.dataset.ccclBreadcrumbsPending = "true";
|
||||
|
||||
const primaryLink = listItem.querySelector("a");
|
||||
if (!primaryLink) {
|
||||
delete listItem.dataset.ccclBreadcrumbsPending;
|
||||
return;
|
||||
}
|
||||
|
||||
const primaryTitle = primaryLink.textContent?.trim() || "";
|
||||
const href = primaryLink.getAttribute("href");
|
||||
const docName = getResultDocNameFromHref(href);
|
||||
if (!docName) {
|
||||
delete listItem.dataset.ccclBreadcrumbsPending;
|
||||
return;
|
||||
}
|
||||
|
||||
const pageInfo = await getPageInfo(docName);
|
||||
if (!pageInfo) {
|
||||
delete listItem.dataset.ccclBreadcrumbsPending;
|
||||
return;
|
||||
}
|
||||
|
||||
const pageTitle = pageInfo.pageTitle || getDocTitle(docName);
|
||||
const breadcrumbs = [...(pageInfo.breadcrumbs || [])];
|
||||
if (pageTitle && primaryTitle && pageTitle !== primaryTitle) {
|
||||
breadcrumbs.push({
|
||||
href: `${docName}${getDocLinkSuffix()}`,
|
||||
title: pageTitle,
|
||||
});
|
||||
}
|
||||
|
||||
if (breadcrumbs.length === 0) {
|
||||
delete listItem.dataset.ccclBreadcrumbsPending;
|
||||
return;
|
||||
}
|
||||
|
||||
const breadcrumbContainer = document.createElement("div");
|
||||
breadcrumbContainer.className = "cccl-search-breadcrumbs";
|
||||
|
||||
breadcrumbs.forEach((breadcrumb) => {
|
||||
const breadcrumbItem = document.createElement("span");
|
||||
breadcrumbItem.className = "breadcrumb-item";
|
||||
const breadcrumbLink = document.createElement("a");
|
||||
breadcrumbLink.href = breadcrumb.href;
|
||||
breadcrumbLink.textContent = breadcrumb.title;
|
||||
breadcrumbItem.appendChild(breadcrumbLink);
|
||||
breadcrumbContainer.appendChild(breadcrumbItem);
|
||||
});
|
||||
|
||||
listItem.insertBefore(breadcrumbContainer, primaryLink.nextSibling);
|
||||
listItem.dataset.ccclBreadcrumbsAttached = "true";
|
||||
delete listItem.dataset.ccclBreadcrumbsPending;
|
||||
};
|
||||
|
||||
const installResultDecorator = () => {
|
||||
if (
|
||||
typeof Search === "undefined" ||
|
||||
Search.__ccclResultDecoratorInstalled ||
|
||||
typeof MutationObserver === "undefined"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalPerformSearch = Search.performSearch;
|
||||
Search.performSearch = (...args) => {
|
||||
const result = originalPerformSearch(...args);
|
||||
const output = Search.output;
|
||||
if (!output) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const decorateTopResults = () => {
|
||||
Array.from(output.querySelectorAll("li"))
|
||||
.slice(0, maxBreadcrumbResults)
|
||||
.forEach(addBreadcrumbTrail);
|
||||
};
|
||||
|
||||
if (Search.__ccclResultsObserver) {
|
||||
Search.__ccclResultsObserver.disconnect();
|
||||
}
|
||||
|
||||
decorateTopResults();
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
decorateTopResults();
|
||||
});
|
||||
|
||||
observer.observe(output, { childList: true, subtree: true });
|
||||
Search.__ccclResultsObserver = observer;
|
||||
Search.__ccclResultDecoratorInstalled = true;
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
const installPostprocess = () => {
|
||||
if (typeof Search === "undefined" || Search.__ccclDedupInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalPerformSearch = Search._performSearch;
|
||||
Search._performSearch = (...args) => {
|
||||
const results = originalPerformSearch(...args);
|
||||
|
||||
// Sphinx keeps results in low->high score order and displays via pop().
|
||||
// Walk from the end so we see the best-ranked result first, but prefer
|
||||
// canonical page links without anchors when collapsing duplicates.
|
||||
const chosen = new Map();
|
||||
for (let i = results.length - 1; i >= 0; --i) {
|
||||
const result = results[i];
|
||||
const title = String(result[1] || "").toLowerCase();
|
||||
const filename = String(result[5] || "");
|
||||
const key = `${filename}\0${title}`;
|
||||
const anchor = String(result[2] || "");
|
||||
const existing = chosen.get(key);
|
||||
if (!existing) {
|
||||
chosen.set(key, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingAnchor = String(existing[2] || "");
|
||||
const prefersCurrent = existingAnchor && !anchor;
|
||||
if (prefersCurrent) {
|
||||
chosen.set(key, result);
|
||||
}
|
||||
}
|
||||
|
||||
const deduped = [];
|
||||
const emitted = new Set();
|
||||
for (let i = 0; i < results.length; ++i) {
|
||||
const result = results[i];
|
||||
const title = String(result[1] || "").toLowerCase();
|
||||
const filename = String(result[5] || "");
|
||||
const key = `${filename}\0${title}`;
|
||||
if (emitted.has(key)) {
|
||||
continue;
|
||||
}
|
||||
const winner = chosen.get(key);
|
||||
if (winner) {
|
||||
winner[1] = decodeEntities(winner[1]);
|
||||
winner[3] = decodeEntities(winner[3]);
|
||||
deduped.push(winner);
|
||||
emitted.add(key);
|
||||
}
|
||||
}
|
||||
return deduped;
|
||||
};
|
||||
|
||||
Search.__ccclDedupInstalled = true;
|
||||
};
|
||||
|
||||
installPostprocess();
|
||||
installResultDecorator();
|
||||
})();
|
||||
Reference in New Issue
Block a user