ronantakizawa/codereview-bench huggingface dataset:
Repository: godotengine/godot
File: editor/scene/gui/control_editor_plugin.cpp (C++)

Code before:
	return selection;
}

void ControlEditorToolbar::_update_anchor_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	int nb_valid_controls = 0;
	int first_preset = -1;
	bool all_preset_same = true;

	const List<Node *> &selection = editor_selection->get_top_selected_node_list();
	for (Node *E : selection) {
		Control *control = Object::cast_to<Control>(E);
		if (!control) {
			continue;
		}
		if (Object::cast_to<Container>(control->get_parent())) {
			continue;
		}

		nb_valid_controls++;

		const Dictionary &state = control->_edit_get_state();
		const int lm = (int)state["layout_mode"];

		if (lm != LayoutMode::LAYOUT_MODE_ANCHORS && lm != LayoutMode::LAYOUT_MODE_UNCONTROLLED) {
			all_preset_same = false;
			break;
		}

		const int preset = (int)state["anchors_layout_preset"];

		if (first_preset == -1) {
			first_preset = preset;
		} else if (preset != first_preset) {
			all_preset_same = false;
			break;
		}
	}

	anchors_picker->set_selected_preset(all_preset_same && nb_valid_controls > 0 ? first_preset : -1);
}

void ControlEditorToolbar::_update_container_sizing_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	bool all_h_shrink_fill_same = true;

Review comment (suggestion):
```suggestion
		const int lm = state["layout_mode"];
```
Same below.

Code after:
	return selection;
}

void ControlEditorToolbar::_update_anchor_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	int nb_valid_controls = 0;
	int first_preset = -1;
	bool all_preset_same = true;

	const List<Node *> &selection = editor_selection->get_top_selected_node_list();
	for (Node *E : selection) {
		Control *control = Object::cast_to<Control>(E);
		if (!control) {
			continue;
		}
		if (Object::cast_to<Container>(control->get_parent())) {
			continue;
		}

		nb_valid_controls++;

		const Dictionary &state = control->_edit_get_state();
		const int lm = state["layout_mode"];

		if (lm != LayoutMode::LAYOUT_MODE_ANCHORS && lm != LayoutMode::LAYOUT_MODE_UNCONTROLLED) {
			all_preset_same = false;
			break;
		}

		const int preset = state["anchors_layout_preset"];

		if (first_preset == -1) {
			first_preset = preset;
		} else if (preset != first_preset) {
			all_preset_same = false;
			break;
		}
	}

	anchors_picker->set_selected_preset((all_preset_same && nb_valid_controls > 0) ? first_preset : -1);
}

void ControlEditorToolbar::_update_container_sizing_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	bool all_h_shrink_fill_same = true;
Repository: godotengine/godot
File: editor/scene/gui/control_editor_plugin.cpp (C++)

Code before:
		}
		if (Object::cast_to<Container>(control->get_parent())) {
			continue;
		}

		nb_valid_controls++;

		const Dictionary &state = control->_edit_get_state();
		const int lm = state["layout_mode"];

		if (lm != LayoutMode::LAYOUT_MODE_ANCHORS && lm != LayoutMode::LAYOUT_MODE_UNCONTROLLED) {
			all_preset_same = false;
			break;
		}

		const int preset = state["anchors_layout_preset"];

		if (first_preset == -1) {
			first_preset = preset;
		} else if (preset != first_preset) {
			all_preset_same = false;
			break;
		}
	}

	anchors_picker->set_selected_preset(all_preset_same && nb_valid_controls > 0 ? first_preset : -1);
}

void ControlEditorToolbar::_update_container_sizing_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	bool all_h_shrink_fill_same = true;
	bool all_v_shrink_fill_same = true;
	bool all_h_expand = true;
	bool all_v_expand = true;
	int first_h_flags = -1;
	int first_v_flags = -1;

	const List<Node *> &selection = editor_selection->get_top_selected_node_list();
	for (Node *E : selection) {
		Control *control = Object::cast_to<Control>(E);
		if (!control) {
			continue;
		}

		const int h_flags = control->get_h_size_flags();
		const int v_flags = control->get_v_size_flags();
		const int h_shrink_fill = h_flags & ~(Control::SIZE_EXPAND);
		const int v_shrink_fill = v_flags & ~(Control::SIZE_EXPAND);

Review comment (suggestion):
```suggestion
	anchors_picker->set_selected_preset((all_preset_same && nb_valid_controls > 0) ? first_preset : -1);
```

Code after:
		}
		if (Object::cast_to<Container>(control->get_parent())) {
			continue;
		}

		nb_valid_controls++;

		const Dictionary &state = control->_edit_get_state();
		const int lm = state["layout_mode"];

		if (lm != LayoutMode::LAYOUT_MODE_ANCHORS && lm != LayoutMode::LAYOUT_MODE_UNCONTROLLED) {
			all_preset_same = false;
			break;
		}

		const int preset = state["anchors_layout_preset"];

		if (first_preset == -1) {
			first_preset = preset;
		} else if (preset != first_preset) {
			all_preset_same = false;
			break;
		}
	}

	anchors_picker->set_selected_preset((all_preset_same && nb_valid_controls > 0) ? first_preset : -1);
}

void ControlEditorToolbar::_update_container_sizing_selection_ui(bool p_pressed) {
	if (!p_pressed) {
		return;
	}

	bool all_h_shrink_fill_same = true;
	bool all_v_shrink_fill_same = true;
	bool all_h_expand = true;
	bool all_v_expand = true;
	int first_h_flags = -1;
	int first_v_flags = -1;

	const List<Node *> &selection = editor_selection->get_top_selected_node_list();
	for (Node *E : selection) {
		Control *control = Object::cast_to<Control>(E);
		if (!control) {
			continue;
		}

		const int h_flags = control->get_h_size_flags();
		const int v_flags = control->get_v_size_flags();
		const int h_shrink_fill = h_flags & ~(Control::SIZE_EXPAND);
		const int v_shrink_fill = v_flags & ~(Control::SIZE_EXPAND);
Repository: godotengine/godot
File: modules/gridmap/grid_map.h (C/C++)

Code before:
	void _notification(int p_what);
	void _update_visibility();
	static void _bind_methods();

public:
	enum {
		INVALID_CELL_ITEM = -1
	};

#ifndef PHYSICS_3D_DISABLED
	void set_collision_layer(uint32_t p_layer);
	uint32_t get_collision_layer() const;

	void set_collision_mask(uint32_t p_mask);
	uint32_t get_collision_mask() const;

	void set_collision_layer_value(int p_layer_number, bool p_value);
	bool get_collision_layer_value(int p_layer_number) const;

	void set_collision_mask_value(int p_layer_number, bool p_value);
	bool get_collision_mask_value(int p_layer_number) const;

	void set_collision_priority(real_t p_priority);
	real_t get_collision_priority() const;

	void set_collision_visibility_mode(DebugVisibilityMode p_show_collision);
	DebugVisibilityMode get_collision_visibility_mode() const;

	void set_physics_material(Ref<PhysicsMaterial> p_material);
	Ref<PhysicsMaterial> get_physics_material() const;

	Array get_collision_shapes() const;
#endif // PHYSICS_3D_DISABLED

	void set_bake_navigation(bool p_bake_navigation);
	bool is_baking_navigation();

#ifndef NAVIGATION_3D_DISABLED
	void set_navigation_map(RID p_navigation_map);
	RID get_navigation_map() const;
#endif // NAVIGATION_3D_DISABLED

	void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
	Ref<MeshLibrary> get_mesh_library() const;

	void set_cell_size(const Vector3 &p_size);
	Vector3 get_cell_size() const;

	void set_octant_size(int p_size);
	int get_octant_size() const;


Review comment (bug):
```suggestion
	void set_collision_visibility_mode(DebugVisibilityMode p_visibility_mode);
```

Code after:
	void _notification(int p_what);
	void _update_visibility();
	static void _bind_methods();

public:
	enum {
		INVALID_CELL_ITEM = -1
	};

#ifndef PHYSICS_3D_DISABLED
	void set_collision_layer(uint32_t p_layer);
	uint32_t get_collision_layer() const;

	void set_collision_mask(uint32_t p_mask);
	uint32_t get_collision_mask() const;

	void set_collision_layer_value(int p_layer_number, bool p_value);
	bool get_collision_layer_value(int p_layer_number) const;

	void set_collision_mask_value(int p_layer_number, bool p_value);
	bool get_collision_mask_value(int p_layer_number) const;

	void set_collision_priority(real_t p_priority);
	real_t get_collision_priority() const;

	void set_collision_visibility_mode(DebugVisibilityMode p_visibility_mode);
	DebugVisibilityMode get_collision_visibility_mode() const;

	void set_physics_material(Ref<PhysicsMaterial> p_material);
	Ref<PhysicsMaterial> get_physics_material() const;

	Array get_collision_shapes() const;
#endif // PHYSICS_3D_DISABLED

	void set_bake_navigation(bool p_bake_navigation);
	bool is_baking_navigation();

#ifndef NAVIGATION_3D_DISABLED
	void set_navigation_map(RID p_navigation_map);
	RID get_navigation_map() const;
#endif // NAVIGATION_3D_DISABLED

	void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
	Ref<MeshLibrary> get_mesh_library() const;

	void set_cell_size(const Vector3 &p_size);
	Vector3 get_cell_size() const;

	void set_octant_size(int p_size);
	int get_octant_size() const;
Repository: godotengine/godot
File: editor/plugins/abstract_polygon_2d_editor.cpp (C++)

Code before:
		if (decomp.is_empty()) {
			continue;
		}
		for (const Vector<Vector2> &sub : decomp) {
			int sub_n_points = sub.size();
			double sub_area2x = 0.0;
			double sub_cx = 0.0;
			double sub_cy = 0.0;
			for (int n = 0; n < sub_n_points; n++) {
				int next = (n + 1 < sub_n_points) ? n + 1 : 0;
				sub_area2x += (sub[n].x * sub[next].y) - (sub[next].x * sub[n].y);
				sub_cx += (sub[n].x + sub[next].x) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
				sub_cy += (sub[n].y + sub[next].y) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
			}
			sub_cx /= (sub_area2x * 3);
			sub_cy /= (sub_area2x * 3);

			cx += sub_cx;
			cy += sub_cy;
		}
		n_subs += decomp.size();
	}
	cx /= n_subs;
	cy /= n_subs;

	return (Vector2(cx, cy));
}

void AbstractPolygon2DEditor::_menu_option(int p_option) {
	switch (p_option) {
		case MODE_CREATE: {
			mode = MODE_CREATE;
			button_create->set_pressed(true);
			button_edit->set_pressed(false);
			button_delete->set_pressed(false);
		} break;
		case MODE_EDIT: {
			_wip_close();
			mode = MODE_EDIT;
			button_create->set_pressed(false);
			button_edit->set_pressed(true);
			button_delete->set_pressed(false);
		} break;
		case MODE_DELETE: {
			_wip_close();
			mode = MODE_DELETE;
			button_create->set_pressed(false);
			button_edit->set_pressed(false);
			button_delete->set_pressed(true);
		} break;
		case CENTER_POLY: {

Review comment (suggestion):
```suggestion
	return Vector2(cx, cy);
```
Too many brackets.

Code after:
		if (decomp.is_empty()) {
			continue;
		}
		for (const Vector<Vector2> &sub : decomp) {
			int sub_n_points = sub.size();
			double sub_area2x = 0.0;
			double sub_cx = 0.0;
			double sub_cy = 0.0;
			for (int n = 0; n < sub_n_points; n++) {
				int next = (n + 1 < sub_n_points) ? n + 1 : 0;
				sub_area2x += (sub[n].x * sub[next].y) - (sub[next].x * sub[n].y);
				sub_cx += (sub[n].x + sub[next].x) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
				sub_cy += (sub[n].y + sub[next].y) * (sub[n].x * sub[next].y - sub[next].x * sub[n].y);
			}
			sub_cx /= (sub_area2x * 3);
			sub_cy /= (sub_area2x * 3);

			cx += sub_cx;
			cy += sub_cy;
		}
		n_subs += decomp.size();
	}
	cx /= n_subs;
	cy /= n_subs;

	return Vector2(cx, cy);
}

void AbstractPolygon2DEditor::_menu_option(int p_option) {
	switch (p_option) {
		case MODE_CREATE: {
			mode = MODE_CREATE;
			button_create->set_pressed(true);
			button_edit->set_pressed(false);
			button_delete->set_pressed(false);
		} break;
		case MODE_EDIT: {
			_wip_close();
			mode = MODE_EDIT;
			button_create->set_pressed(false);
			button_edit->set_pressed(true);
			button_delete->set_pressed(false);
		} break;
		case MODE_DELETE: {
			_wip_close();
			mode = MODE_DELETE;
			button_create->set_pressed(false);
			button_edit->set_pressed(false);
			button_delete->set_pressed(true);
		} break;
		case CENTER_POLY: {
Repository: godotengine/godot
File: scene/2d/camera_2d.cpp (C++)

Code before:

	if (is_current) {
		viewport->_camera_2d_set(this);
	} else if (was_current) {
		viewport->_camera_2d_set(nullptr);
	}

	if (is_current != was_current) {
		_update_process_callback();
	}
}

void Camera2D::set_limit_rect(const Rect2i &p_limit_rect) {
	const Point2i limit_rect_end = p_limit_rect.get_end();
	set_limit(SIDE_LEFT, p_limit_rect.position.x);
	set_limit(SIDE_TOP, p_limit_rect.position.y);
	set_limit(SIDE_RIGHT, limit_rect_end.x);
	set_limit(SIDE_BOTTOM, limit_rect_end.y);
}

Rect2i Camera2D::get_limit_rect() const {
	return Rect2i(limit[SIDE_LEFT], limit[SIDE_TOP], limit[SIDE_RIGHT] - limit[SIDE_LEFT], limit[SIDE_BOTTOM] - limit[SIDE_TOP]);
}

void Camera2D::make_current() {
	ERR_FAIL_COND(!enabled || !is_inside_tree());
	get_tree()->call_group(group_name, "_make_current", this);
	if (just_exited_tree) {
		// If camera exited the scene tree in the same frame, group call will skip it, so this needs to be called manually.
		_make_current(this);
	}
	_update_scroll();
	_update_process_callback();
}

void Camera2D::clear_current() {
	ERR_FAIL_COND(!is_current());

	if (!viewport || !viewport->is_inside_tree()) {
		return;
	}

	if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) {
		viewport->assign_next_enabled_camera_2d(group_name);
	}

	_update_process_callback();
}

bool Camera2D::is_current() const {
	if (!viewport) {

Review comment (suggestion):
Shouldn't the limits be real_t instead? Since they limit the effective camera position which is a Point2, not a Point2i.

Code after:
void Camera2D::_make_current(Object *p_which) {
	if (!is_inside_tree() || !viewport) {
		return;
	}

	if (custom_viewport && !ObjectDB::get_instance(custom_viewport_id)) {
		return;
	}

	queue_redraw();

	bool was_current = viewport->get_camera_2d() == this;
	bool is_current = p_which == this;

	if (is_current) {
		viewport->_camera_2d_set(this);
	} else if (was_current) {
		viewport->_camera_2d_set(nullptr);
	}

	if (is_current != was_current) {
		_update_process_callback();
	}
}

void Camera2D::set_limit_rect(const Rect2i &p_limit_rect) {
	const Point2i limit_rect_end = p_limit_rect.get_end();
	set_limit(SIDE_LEFT, p_limit_rect.position.x);
	set_limit(SIDE_TOP, p_limit_rect.position.y);
	set_limit(SIDE_RIGHT, limit_rect_end.x);
	set_limit(SIDE_BOTTOM, limit_rect_end.y);
}

Rect2i Camera2D::get_limit_rect() const {
	return Rect2i(limit[SIDE_LEFT], limit[SIDE_TOP], limit[SIDE_RIGHT] - limit[SIDE_LEFT], limit[SIDE_BOTTOM] - limit[SIDE_TOP]);
}

void Camera2D::make_current() {
	ERR_FAIL_COND(!enabled || !is_inside_tree());
	get_tree()->call_group(group_name, "_make_current", this);
	if (just_exited_tree) {
		// If camera exited the scene tree in the same frame, group call will skip it, so this needs to be called manually.
		_make_current(this);
	}
	_update_scroll();
	_update_process_callback();
}

void Camera2D::clear_current() {
	ERR_FAIL_COND(!is_current());
Repository: godotengine/godot
File: scene/2d/camera_2d.h (C/C++)

Code before:

	bool limit_enabled = true;
	int limit[4] = { -10000000, -10000000, 10000000, 10000000 }; // Left, top, right, bottom.
	bool limit_smoothing_enabled = false;

	real_t drag_margin[4] = { 0.2, 0.2, 0.2, 0.2 };
	bool drag_horizontal_enabled = false;
	bool drag_vertical_enabled = false;
	real_t drag_horizontal_offset = 0.0;
	real_t drag_vertical_offset = 0.0;
	bool drag_horizontal_offset_changed = false;
	bool drag_vertical_offset_changed = false;

	Point2 camera_screen_center;
	bool _is_editing_in_editor() const;
	void _update_process_callback();
	void _update_scroll();

#ifdef TOOLS_ENABLED
	void _project_settings_changed();
#endif

	void _make_current(Object *p_which);
	void _reset_just_exited() { just_exited_tree = false; }

	void _update_process_internal_for_smoothing();

	bool screen_drawing_enabled = true;
	bool limit_drawing_enabled = false;
	bool margin_drawing_enabled = false;

	Camera2DProcessCallback process_callback = CAMERA2D_PROCESS_IDLE;

	struct InterpolationData {
		Transform2D xform_curr;
		Transform2D xform_prev;
		uint32_t last_update_physics_tick = UINT32_MAX; // Ensure tick 0 is detected as a change.
	} _interpolation_data;

	void _ensure_update_interpolation_data();

	Size2 _get_camera_screen_size() const;

protected:
	virtual Transform2D get_camera_transform();

	void _notification(int p_what);
	static void _bind_methods();
	void _validate_property(PropertyInfo &p_property) const;

public:

Review comment (suggestion):
Unrelated, but this method is unused and can be removed.
Same with `_is_editing_in_editor` above.

Code after:

	bool limit_enabled = true;
	int limit[4] = { -10000000, -10000000, 10000000, 10000000 }; // Left, top, right, bottom.
	bool limit_smoothing_enabled = false;

	real_t drag_margin[4] = { 0.2, 0.2, 0.2, 0.2 };
	bool drag_horizontal_enabled = false;
	bool drag_vertical_enabled = false;
	real_t drag_horizontal_offset = 0.0;
	real_t drag_vertical_offset = 0.0;
	bool drag_horizontal_offset_changed = false;
	bool drag_vertical_offset_changed = false;

	Point2 camera_screen_center;
	bool _is_editing_in_editor() const;
	void _update_process_callback();
	void _update_scroll();

#ifdef TOOLS_ENABLED
	void _project_settings_changed();
#endif

	void _make_current(Object *p_which);
	void _reset_just_exited() { just_exited_tree = false; }

	void _update_process_internal_for_smoothing();

	bool screen_drawing_enabled = true;
	bool limit_drawing_enabled = false;
	bool margin_drawing_enabled = false;

	Camera2DProcessCallback process_callback = CAMERA2D_PROCESS_IDLE;

	struct InterpolationData {
		Transform2D xform_curr;
		Transform2D xform_prev;
		uint32_t last_update_physics_tick = UINT32_MAX; // Ensure tick 0 is detected as a change.
	} _interpolation_data;

	void _ensure_update_interpolation_data();

	Size2 _get_camera_screen_size() const;

protected:
	virtual Transform2D get_camera_transform();

	void _notification(int p_what);
	static void _bind_methods();

public:
	void set_limit_rect(const Rect2i &p_limit_rect);
Repository: godotengine/godot
File: core/templates/span.h (C/C++)

Code before:
	return -1;
}

template <typename T>
constexpr int64_t Span<T>::rfind(const T &p_val, int64_t p_from) const {
	const int64_t s = size();

	if (p_from < 0) {
		p_from = s + p_from;
	}
	if (p_from < 0 || p_from >= s) {
		p_from = s - 1;
	}

	for (int64_t i = p_from; i >= 0; i--) {
		if (ptr()[i] == p_val) {
			return i;
		}
	}
	return -1;
}

template <typename T>
constexpr int64_t Span<T>::rfind_seq(const Span<T> &p_span, int64_t p_from) const {
	const int64_t s = size();
	const int64_t p_s = p_span.size();

	if (p_s == 0 || p_s > s){
		return -1;
	}

	if (p_s == 1){
		return rfind(p_span.ptr()[0], p_from);
	}

	if (p_from < 0) {
		p_from = s + p_from;
	}
	if (p_from < 0 || p_from >= s) {
		p_from = s - 1;
	}
	if (p_from > s - p_s){
		p_from = s - p_s;
	}

	for (int64_t i = p_from; i >= 0; i--) {
		bool found = true;
		for (int64_t j = 0; j < p_s; j++){
			if(ptr()[i + j] != p_span.ptr()[j]){
				found = false;
				break;

Review comment (performance):
I think both variables would be better inlined (aka use `size()` instead of `s` everywhere). The `size()` function is guaranteed to be inlined, so it's not a performance concern, and I think `size()` is more readable than `s` :)

Code after:
			return i;
		}
	}
	return -1;
}

template <typename T>
constexpr int64_t Span<T>::find_sequence(const Span<T> &p_span, uint64_t p_from) const {
	for (uint64_t i = p_from; i <= size() - p_span.size(); i++) {
		bool found = true;
		for (uint64_t j = 0; j < p_span.size(); j++) {
			if (ptr()[i + j] != p_span.ptr()[j]) {
				found = false;
				break;
			}
		}
		if (found) {
			return i;
		}
	}

	return -1;
}

template <typename T>
constexpr int64_t Span<T>::rfind(const T &p_val, uint64_t p_from) const {
	for (int64_t i = p_from; i >= 0; i--) {
		if (ptr()[i] == p_val) {
			return i;
		}
	}
	return -1;
}

template <typename T>
constexpr int64_t Span<T>::rfind_sequence(const Span<T> &p_span, uint64_t p_from) const {
	for (int64_t i = p_from; i >= 0; i--) {
		bool found = true;
		for (uint64_t j = 0; j < p_span.size(); j++) {
			if (ptr()[i + j] != p_span.ptr()[j]) {
				found = false;
				break;
			}
		}
		if (found) {
			return i;
		}
	}

	return -1;
}
Repository: godotengine/godot
File: core/string/ustring.cpp (C++)

Code before:
			}

			char32_t src = _find_lower(srcd[read_pos]);
			char32_t dst = _find_lower(p_str[j]);

			if (src != dst) {
				found = false;
				break;
			}
		}

		if (found) {
			return i;
		}
	}

	return -1;
}

int String::rfind(const String &p_str, int p_from) const {
	if (p_str.length() == 0 || p_str.length() > length()){
		return -1;
	}

	if (p_str.length() == 1){
		return span().rfind(p_str[0], p_from);
	}

	if (p_from < 0) {
		p_from = length() + p_from;
	}
	if (p_from < 0 || p_from >= length()) {
		p_from = length() - 1;
	}
	if (p_from > length() - p_str.length()){
		p_from = length() - p_str.length();
	}

	return span().rfind_seq(p_str.span(), p_from);
}

int String::rfind(const char *p_str, int p_from) const {
	const int source_length = length();
	int substring_length = strlen(p_str);

	if (source_length == 0 || substring_length == 0) {
		return -1; // won't find anything!
	}

	// establish a limit
	int limit = length() - substring_length;

Review comment (performance):
I think i'd prefer to keep a comment here (similar with the other functions):
```suggestion
		// Optimize with single-char implementation.
		return span().rfind(p_str[0], p_from);
```
The reason being that it takes complexity away from the code by explaining why we have this special case :)

Code after:

	return true;
}

bool String::begins_with(const String &p_string) const {
	const int l = p_string.length();
	if (l > length()) {
		return false;
	}
	if (l == 0) {
		return true;
	}

	return memcmp(ptr(), p_string.ptr(), l * sizeof(char32_t)) == 0;
}

bool String::begins_with(const char *p_string) const {
	if (!p_string) {
		return false;
	}

	int l = length();
	if (l == 0) {
		return *p_string == 0;
	}

	const char32_t *str = &operator[](0);
	int i = 0;

	while (*p_string && i < l) {
		if ((char32_t)*p_string != str[i]) {
			return false;
		}
		i++;
		p_string++;
	}

	return *p_string == 0;
}

bool String::is_enclosed_in(const String &p_string) const {
	return begins_with(p_string) && ends_with(p_string);
}

bool String::is_subsequence_of(const String &p_string) const {
	return _base_is_subsequence_of(p_string, false);
}

bool String::is_subsequence_ofn(const String &p_string) const {
	return _base_is_subsequence_of(p_string, true);
}