Skip to content

Commit c0bfba7

Browse files
committed
cpp: Add GGUFReader.cpp and GGUFReader.kt to read GGUF files #34
1 parent 93c3bde commit c0bfba7

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

smollm/src/main/cpp/GGUFReader.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "gguf.h"
2+
#include <jni.h>
3+
#include <string>
4+
5+
extern "C"
6+
JNIEXPORT jlong JNICALL
7+
Java_io_shubham0204_smollm_GGUFReader_getGGUFContextNativeHandle(JNIEnv *env, jobject thiz, jstring modelPath) {
8+
jboolean isCopy = true;
9+
const char *modelPathCStr = env->GetStringUTFChars(modelPath, &isCopy);
10+
gguf_init_params initParams = {
11+
.no_alloc = true,
12+
.ctx = nullptr
13+
};
14+
gguf_context *ggufContext = gguf_init_from_file(modelPathCStr, initParams);
15+
env->ReleaseStringUTFChars(modelPath, modelPathCStr);
16+
return reinterpret_cast<jlong>(ggufContext);
17+
}
18+
19+
extern "C"
20+
JNIEXPORT jlong JNICALL
21+
Java_io_shubham0204_smollm_GGUFReader_getContextSize(JNIEnv *env, jobject thiz, jlong nativeHandle) {
22+
gguf_context *ggufContext = reinterpret_cast<gguf_context *>(nativeHandle);
23+
int64_t architectureKeyId = gguf_find_key(ggufContext, "general.architecture");
24+
if (architectureKeyId == -1) return -1;
25+
std::string architecture = gguf_get_val_str(ggufContext, architectureKeyId);
26+
std::string contextLengthKey = architecture + ".context_length";
27+
int64_t contextLengthKeyId = gguf_find_key(ggufContext, contextLengthKey.c_str());
28+
if (contextLengthKeyId == -1) return -1;
29+
uint32_t contextLength = gguf_get_val_u32(ggufContext, contextLengthKeyId);
30+
return contextLength;
31+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (C) 2025 Shubham Panchal
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.shubham0204.smollm
18+
19+
import kotlinx.coroutines.Dispatchers
20+
import kotlinx.coroutines.withContext
21+
22+
class GGUFReader {
23+
companion object {
24+
init {
25+
System.loadLibrary("ggufreader")
26+
}
27+
}
28+
29+
private var nativeHandle: Long = 0L
30+
31+
suspend fun load(modelPath: String) =
32+
withContext(Dispatchers.IO) {
33+
nativeHandle = getGGUFContextNativeHandle(modelPath)
34+
}
35+
36+
fun getContextSize(): Long? {
37+
assert(nativeHandle != 0L) { "Use GGUFReader.load() to initialize the reader" }
38+
val contextSize = getContextSize(nativeHandle)
39+
return if (contextSize == -1L) {
40+
null
41+
} else {
42+
contextSize
43+
}
44+
}
45+
46+
/**
47+
* Returns the native handle (pointer to gguf_context created on the native side)
48+
*/
49+
private external fun getGGUFContextNativeHandle(modelPath: String): Long
50+
51+
/**
52+
* Read the context size (in no. of tokens) from the GGUF file, given the native handle
53+
*/
54+
private external fun getContextSize(nativeHandle: Long): Long
55+
}

0 commit comments

Comments
 (0)