Skip to content

Instantly share code, notes, and snippets.

@nicolasmelo1
Created April 27, 2026 20:10
Show Gist options
  • Select an option

  • Save nicolasmelo1/24fe75e7b6f233e7a2c5cd8bcf682afa to your computer and use it in GitHub Desktop.

Select an option

Save nicolasmelo1/24fe75e7b6f233e7a2c5cd8bcf682afa to your computer and use it in GitHub Desktop.
Check if its a palindrome
#import <Metal/Metal.h>
#include <iostream>
#include <cstring>
int main() {
@autoreleasepool {
const char* input = "Anotaram a data da maratona";
NSString *objcString = [NSString stringWithUTF8String:input];
NSString *lowerString = [objcString lowercaseString];
NSString *normalized = [[lowerString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""];
const char *lowerCStr = [normalized UTF8String];
uint32_t n = (uint32_t)strlen(lowerCStr);
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (!device) {
std::cerr << "Metal is not supported on this device.\n";
return 1;
}
NSError* error = nil;
NSString* shaderPath = @"palindrome.metal";
NSString* shaderSource =
[NSString stringWithContentsOfFile:shaderPath
encoding:NSUTF8StringEncoding
error:&error];
if (!shaderSource) {
std::cerr << "Failed to read palindrome.metal\n";
return 1;
}
id<MTLLibrary> library =
[device newLibraryWithSource:shaderSource
options:nil
error:&error];
if (!library) {
std::cerr << "Failed to compile Metal shader: "
<< [[error localizedDescription] UTF8String] << "\n";
return 1;
}
id<MTLFunction> function =
[library newFunctionWithName:@"palindromeKernel"];
if (!function) {
std::cerr << "Failed to find palindromeKernel.\n";
return 1;
}
id<MTLComputePipelineState> pipeline =
[device newComputePipelineStateWithFunction:function
error:&error];
if (!pipeline) {
std::cerr << "Failed to create compute pipeline: "
<< [[error localizedDescription] UTF8String] << "\n";
return 1;
}
id<MTLCommandQueue> commandQueue = [device newCommandQueue];
uint32_t initialResult = 1;
id<MTLBuffer> stringBuffer =
[device newBufferWithBytes:lowerCStr
length:n * sizeof(char)
options:MTLResourceStorageModeShared];
id<MTLBuffer> lengthBuffer =
[device newBufferWithBytes:&n
length:sizeof(uint32_t)
options:MTLResourceStorageModeShared];
id<MTLBuffer> resultBuffer =
[device newBufferWithBytes:&initialResult
length:sizeof(uint32_t)
options:MTLResourceStorageModeShared];
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
id<MTLComputeCommandEncoder> encoder =
[commandBuffer computeCommandEncoder];
[encoder setComputePipelineState:pipeline];
[encoder setBuffer:stringBuffer offset:0 atIndex:0];
[encoder setBuffer:lengthBuffer offset:0 atIndex:1];
[encoder setBuffer:resultBuffer offset:0 atIndex:2];
NSUInteger threadsNeeded = n / 2;
NSUInteger threadsPerThreadgroup = 256;
MTLSize gridSize = MTLSizeMake(threadsNeeded, 1, 1);
MTLSize threadgroupSize = MTLSizeMake(threadsPerThreadgroup, 1, 1);
[encoder dispatchThreads:gridSize
threadsPerThreadgroup:threadgroupSize];
[encoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
uint32_t result =
*static_cast<uint32_t*>([resultBuffer contents]);
if (result == 1) {
std::cout << input << " is a palindrome\n";
} else {
std::cout << input << " is not a palindrome\n";
}
}
return 0;
}
#include <metal_stdlib>
using namespace metal;
kernel void palindromeKernel(
device const char* str [[buffer(0)]],
constant uint& n [[buffer(1)]],
device atomic_uint* result [[buffer(2)]],
uint id [[thread_position_in_grid]]
) {
if (id < n / 2) {
char left = str[id];
char right = str[n - 1 - id];
if (left != right) {
atomic_store_explicit(result, 0, memory_order_relaxed);
}
}
}
@nicolasmelo1

nicolasmelo1 commented Apr 27, 2026

Copy link
Copy Markdown
Author
$  clang main.m -framework Metal -framework Foundation -o palindrome_metal
$ ./palindrome_metal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment