#define _POSIX_C_SOURCE 200809L #include "runtime.h" #include "../utils/safe_alloc.h" #include #include #include #include static inline uint32_t _rava_field_hash(const char *name) { uint32_t hash = 5381; while (*name) { hash = ((hash << 5) + hash) ^ (uint32_t)*name++; } return hash; } RavaObject_t* rava_object_create(const char *class_name) { RavaObject_t *obj = calloc(1, sizeof(RavaObject_t)); if (!obj) return NULL; obj->class_name = strdup(class_name); obj->field_capacity = 8; obj->field_names = calloc(obj->field_capacity, sizeof(char*)); obj->field_values = calloc(obj->field_capacity, sizeof(RavaValue_t)); if (!obj->field_names || !obj->field_values) { free(obj->field_names); free(obj->field_values); free(obj->class_name); free(obj); return NULL; } obj->field_count = 0; for (int i = 0; i < RAVA_OBJECT_HASH_SIZE; i++) { obj->field_hash[i] = -1; } return obj; } void rava_object_destroy(RavaObject_t *obj) { if (!obj) return; free(obj->class_name); for (size_t i = 0; i < obj->field_count; i++) { free(obj->field_names[i]); } free(obj->field_names); free(obj->field_values); free(obj); } void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) { if (!obj || !name) return; uint32_t hash = _rava_field_hash(name); for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) { uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1); int field_idx = obj->field_hash[idx]; if (field_idx == -1) { if (obj->field_count >= obj->field_capacity) { size_t new_cap = obj->field_capacity * 2; char **new_names = rava_safe_realloc(obj->field_names, new_cap * sizeof(char*)); RavaValue_t *new_values = rava_safe_realloc(obj->field_values, new_cap * sizeof(RavaValue_t)); if (!new_names || !new_values) return; obj->field_names = new_names; obj->field_values = new_values; obj->field_capacity = new_cap; } obj->field_names[obj->field_count] = strdup(name); obj->field_values[obj->field_count] = value; obj->field_hash[idx] = (int)obj->field_count; obj->field_count++; return; } if ((size_t)field_idx < obj->field_count && strcmp(obj->field_names[field_idx], name) == 0) { obj->field_values[field_idx] = value; return; } } } RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name) { if (!obj || !name) return rava_value_null(); uint32_t hash = _rava_field_hash(name); for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) { uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1); int field_idx = obj->field_hash[idx]; if (field_idx == -1) { return rava_value_null(); } if ((size_t)field_idx < obj->field_count && strcmp(obj->field_names[field_idx], name) == 0) { return obj->field_values[field_idx]; } } return rava_value_null(); } int rava_object_get_field_index(RavaObject_t *obj, const char *name) { if (!obj || !name) return -1; uint32_t hash = _rava_field_hash(name); for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) { uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1); int field_idx = obj->field_hash[idx]; if (field_idx == -1) return -1; if ((size_t)field_idx < obj->field_count && strcmp(obj->field_names[field_idx], name) == 0) { return field_idx; } } return -1; } RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index) { if (!obj || index < 0 || (size_t)index >= obj->field_count) { return rava_value_null(); } return obj->field_values[index]; } void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value) { if (!obj || index < 0 || (size_t)index >= obj->field_count) return; obj->field_values[index] = value; } int32_t rava_object_hashcode(RavaValue_t value) { switch (value.type) { case RAVA_VAL_NULL: return 0; case RAVA_VAL_INT: return value.data.int_val; case RAVA_VAL_LONG: { int64_t v = value.data.long_val; return (int32_t)(v ^ (v >> 32)); } case RAVA_VAL_FLOAT: { union { float f; int32_t i; } u; u.f = value.data.float_val; return u.i; } case RAVA_VAL_DOUBLE: { union { double d; int64_t l; } u; u.d = value.data.double_val; return (int32_t)(u.l ^ (u.l >> 32)); } case RAVA_VAL_BOOLEAN: return value.data.bool_val ? 1231 : 1237; case RAVA_VAL_CHAR: return (int32_t)value.data.char_val; case RAVA_VAL_STRING: { if (!value.data.string_val) return 0; int32_t hash = 0; for (const char *p = value.data.string_val; *p; p++) { hash = 31 * hash + (int32_t)(unsigned char)*p; } return hash; } case RAVA_VAL_OBJECT: case RAVA_VAL_ARRAY: case RAVA_VAL_ARRAYLIST: case RAVA_VAL_HASHMAP: return (int32_t)((uintptr_t)value.data.object_val >> 3); case RAVA_VAL_SOCKET: return (int32_t)((uintptr_t)value.data.socket_val >> 3); case RAVA_VAL_STREAM: return (int32_t)((uintptr_t)value.data.stream_val >> 3); case RAVA_VAL_METHOD_REF: return (int32_t)((uintptr_t)value.data.method_ref_val >> 3); } return 0; } bool rava_object_equals(RavaValue_t a, RavaValue_t b) { if (a.type == RAVA_VAL_NULL && b.type == RAVA_VAL_NULL) { return true; } if (a.type == RAVA_VAL_NULL || b.type == RAVA_VAL_NULL) { return false; } if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING) { if (!a.data.string_val && !b.data.string_val) return true; if (!a.data.string_val || !b.data.string_val) return false; return strcmp(a.data.string_val, b.data.string_val) == 0; } if (a.type != b.type) { return false; } switch (a.type) { case RAVA_VAL_INT: return a.data.int_val == b.data.int_val; case RAVA_VAL_LONG: return a.data.long_val == b.data.long_val; case RAVA_VAL_FLOAT: return a.data.float_val == b.data.float_val; case RAVA_VAL_DOUBLE: return a.data.double_val == b.data.double_val; case RAVA_VAL_BOOLEAN: return a.data.bool_val == b.data.bool_val; case RAVA_VAL_CHAR: return a.data.char_val == b.data.char_val; case RAVA_VAL_OBJECT: case RAVA_VAL_ARRAY: case RAVA_VAL_ARRAYLIST: case RAVA_VAL_HASHMAP: return a.data.object_val == b.data.object_val; default: return false; } } char* rava_object_tostring(RavaValue_t value) { char *buffer = malloc(128); if (!buffer) return NULL; switch (value.type) { case RAVA_VAL_NULL: strcpy(buffer, "null"); break; case RAVA_VAL_INT: snprintf(buffer, 128, "%d", value.data.int_val); break; case RAVA_VAL_LONG: snprintf(buffer, 128, "%ld", value.data.long_val); break; case RAVA_VAL_FLOAT: snprintf(buffer, 128, "%g", (double)value.data.float_val); break; case RAVA_VAL_DOUBLE: snprintf(buffer, 128, "%g", value.data.double_val); break; case RAVA_VAL_BOOLEAN: strcpy(buffer, value.data.bool_val ? "true" : "false"); break; case RAVA_VAL_CHAR: snprintf(buffer, 128, "%c", value.data.char_val); break; case RAVA_VAL_STRING: free(buffer); return value.data.string_val ? strdup(value.data.string_val) : strdup("null"); case RAVA_VAL_OBJECT: if (!value.data.object_val) { strcpy(buffer, "null"); } else { snprintf(buffer, 128, "%s@%x", value.data.object_val->class_name, (unsigned int)((uintptr_t)value.data.object_val >> 3)); } break; case RAVA_VAL_ARRAY: if (!value.data.array_val) { strcpy(buffer, "null"); } else { snprintf(buffer, 128, "[array@%x]", (unsigned int)((uintptr_t)value.data.array_val >> 3)); } break; case RAVA_VAL_ARRAYLIST: snprintf(buffer, 128, "ArrayList@%x", (unsigned int)((uintptr_t)value.data.arraylist_val >> 3)); break; case RAVA_VAL_HASHMAP: snprintf(buffer, 128, "HashMap@%x", (unsigned int)((uintptr_t)value.data.hashmap_val >> 3)); break; case RAVA_VAL_SOCKET: snprintf(buffer, 128, "Socket@%x", (unsigned int)((uintptr_t)value.data.socket_val >> 3)); break; case RAVA_VAL_STREAM: snprintf(buffer, 128, "Stream@%x", (unsigned int)((uintptr_t)value.data.stream_val >> 3)); break; case RAVA_VAL_METHOD_REF: if (value.data.method_ref_val) { snprintf(buffer, 128, "%s::%s", value.data.method_ref_val->class_name ? value.data.method_ref_val->class_name : "", value.data.method_ref_val->method_name ? value.data.method_ref_val->method_name : ""); } else { strcpy(buffer, "null"); } break; } return buffer; } const char* rava_object_getclass(RavaValue_t value) { switch (value.type) { case RAVA_VAL_NULL: return "null"; case RAVA_VAL_INT: return "Integer"; case RAVA_VAL_LONG: return "Long"; case RAVA_VAL_FLOAT: return "Float"; case RAVA_VAL_DOUBLE: return "Double"; case RAVA_VAL_BOOLEAN: return "Boolean"; case RAVA_VAL_CHAR: return "Character"; case RAVA_VAL_STRING: return "String"; case RAVA_VAL_OBJECT: if (value.data.object_val) { return value.data.object_val->class_name; } return "null"; case RAVA_VAL_ARRAY: return "Array"; case RAVA_VAL_ARRAYLIST: return "ArrayList"; case RAVA_VAL_HASHMAP: return "HashMap"; case RAVA_VAL_SOCKET: return "Socket"; case RAVA_VAL_STREAM: return "Stream"; case RAVA_VAL_METHOD_REF: return "MethodReference"; } return "Object"; }