Repository: duckdb/duckdb
File: src/execution/index/art/prefix.cpp (C++)

Code before:
		// The split is at the last prefix byte, but the prefix is not full.
		// There are no other bytes or prefixes after the split.
		// We get:
		// [this prefix minus split byte (can be its only byte, then we free it)] ->
		// [new node at split byte] ->
		// [child at split byte: prefix.ptr].
		child = *prefix.ptr;
	}

	// Set the new count of this node (can be empty).
	prefix.data[Count(art)] = pos;

	// No bytes left before the split, free this node.
	if (pos == 0) {
		auto old_status = node.get().GetGateStatus();
		Node::FreeNode(art, node);
		return old_status;
	}

	// There are bytes left before the split.
	// The subsequent node replaces the split byte.
	node = *prefix.ptr;
	return GateStatus::GATE_NOT_SET;
}

string Prefix::ToString(ART &art, const Node &node, idx_t indent_level, bool inside_gate, bool display_ascii,
                        optional_ptr<const ARTKey> key_path, idx_t key_depth, idx_t depth_remaining,
                        bool print_deprecated_leaves, bool structure_only) {
	auto indent = [](string &str, const idx_t n) {
		for (idx_t i = 0; i < n; ++i) {
			str += " ";
		}
	};
	auto format_byte = [&](uint8_t byte) {
		if (!inside_gate && display_ascii && byte >= 32 && byte <= 126) {
			return string(1, static_cast<char>(byte));
		}
		return to_string(byte);
	};
	string str = "";
	indent(str, indent_level);
	reference<const Node> ref(node);
	Iterator(art, ref, true, false, [&](const Prefix &prefix) {
		str += "Prefix: |";
		idx_t prefix_len = prefix.data[Count(art)];
		for (idx_t i = 0; i < prefix_len; i++) {
			str += format_byte(prefix.data[i]) + "|";
			if (key_path) {
				key_depth++;
			}
		}

Review comment (suggestion):
That's quite a few parameters. Could we wrap them in a struct?
It would also make the descriptions of the parameters more legible with the comments you added in the header.

Code after:
		// The split is at the last prefix byte, but the prefix is not full.
		// There are no other bytes or prefixes after the split.
		// We get:
		// [this prefix minus split byte (can be its only byte, then we free it)] ->
		// [new node at split byte] ->
		// [child at split byte: prefix.ptr].
		child = *prefix.ptr;
	}

	// Set the new count of this node (can be empty).
	prefix.data[Count(art)] = pos;

	// No bytes left before the split, free this node.
	if (pos == 0) {
		auto old_status = node.get().GetGateStatus();
		Node::FreeNode(art, node);
		return old_status;
	}

	// There are bytes left before the split.
	// The subsequent node replaces the split byte.
	node = *prefix.ptr;
	return GateStatus::GATE_NOT_SET;
}

string Prefix::ToString(ART &art, const Node &node, const ToStringOptions &options) {
	auto indent = [](string &str, const idx_t n) {
		str.append(n, ' ');
	};
	auto format_byte = [&](uint8_t byte) {
		if (!options.inside_gate && options.display_ascii && byte >= 32 && byte <= 126) {
			return string(1, static_cast<char>(byte));
		}
		return to_string(byte);
	};
	string str = "";
	indent(str, options.indent_level);
	reference<const Node> ref(node);
	ToStringOptions child_options = options;
	Iterator(art, ref, true, false, [&](const Prefix &prefix) {
		str += "Prefix: |";
		idx_t prefix_len = prefix.data[Count(art)];
		for (idx_t i = 0; i < prefix_len; i++) {
			str += format_byte(prefix.data[i]) + "|";
			if (options.key_path) {
				child_options.key_depth++;
			}
		}
	});
	string child = ref.get().ToString(art, child_options);
	return str + "\n" + child;