mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
Remove _IS_NUMERIC macro in favor of concrete funtion CPIsNumeric()
- Create Foundation/_CPFoundationUtilities.j to house global low-level utilities. - Implement CPIsNumeric as a concrete JavaScript function, preserving the exact legacy logic. - Import _CPFoundationUtilities.j in the Foundation.j umbrella manifest. - Replace _IS_NUMERIC macro calls at all call sites with CPIsNumeric().
This commit is contained in:
+2
-3
@@ -23,12 +23,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPAnimation.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
@@ -259,7 +258,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
*/
|
||||
- (void)setKnobProportion:(float)aProportion
|
||||
{
|
||||
if (!_IS_NUMERIC(aProportion))
|
||||
if (!CPIsNumeric(aProportion))
|
||||
[CPException raise:CPInvalidArgumentException reason:"aProportion must be numeric, was: "+aProportion];
|
||||
|
||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||
|
||||
@@ -23,13 +23,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPTrackingArea.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPUserDefaults
|
||||
@global CPApp
|
||||
@@ -1171,7 +1169,7 @@ var CPThemeStatesForSplitViewDivider = @[@"dummy one as CPSplitViewDividerStyle
|
||||
// Silently ignore bad positions which could result from odd delegate responses. We don't want these
|
||||
// bad results to go into the system and cause havoc with frame sizes as the split view tries to resize
|
||||
// its subviews.
|
||||
if (_IS_NUMERIC(proposedPosition))
|
||||
if (CPIsNumeric(proposedPosition))
|
||||
position = proposedPosition;
|
||||
|
||||
var proposedMax = [self maxPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
@@ -1181,10 +1179,10 @@ var CPThemeStatesForSplitViewDivider = @[@"dummy one as CPSplitViewDividerStyle
|
||||
proposedActualMin = [self _sendDelegateSplitViewConstrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex],
|
||||
proposedActualMax = [self _sendDelegateSplitViewConstrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMin))
|
||||
if (CPIsNumeric(proposedActualMin))
|
||||
actualMin = proposedActualMin;
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMax))
|
||||
if (CPIsNumeric(proposedActualMax))
|
||||
actualMax = proposedActualMax;
|
||||
|
||||
var viewA = _arrangedSubviews[dividerIndex],
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
// Gravity Areas
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Foundation.h"
|
||||
|
||||
@import "CPArray.j"
|
||||
@import "CPObject.j"
|
||||
@import "CPRange.j"
|
||||
@@ -79,7 +77,7 @@
|
||||
*/
|
||||
- (id)initWithIndex:(CPInteger)anIndex
|
||||
{
|
||||
if (!_IS_NUMERIC(anIndex))
|
||||
if (!CPIsNumeric(anIndex))
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:"Invalid index"];
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// By Christian C. Salvadó, http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844
|
||||
#define _IS_NUMERIC(n) (!isNaN(parseFloat(n)) && isFinite(n))
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import "_CGGeometry.j"
|
||||
@import "_CPFoundationUtilities.j"
|
||||
@import "CPArray.j"
|
||||
@import "CPBundle.j"
|
||||
@import "CPByteCountFormatter.j"
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* _CPFoundationUtilities.j
|
||||
* Foundation
|
||||
*
|
||||
* Created by David Richardson.
|
||||
* Copyright 2026, Cappuccino Project.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//#define _IS_NUMERIC(n) (!isNaN(parseFloat(n)) && isFinite(n))
|
||||
|
||||
/*
|
||||
Objective-J is a strict superset of JavaScript and compiles down to a shared global runtime scope.
|
||||
This file (_CPFoundationUtilities.j) is the canonical place for otherwise "homeless" low-level
|
||||
utilities, stateless helpers, and former C-style preprocessor macros that do not belong to a
|
||||
specific class but are required across the framework.
|
||||
|
||||
While modern JavaScript ecosystems (e.g., ES6 modules, bundlers) treat the global scope as something
|
||||
to be strictly avoided, Cappuccino's architecture predates these paradigms. It relies entirely on
|
||||
global scope sharing for its runtime and toll-free bridging with native JavaScript, much like C and
|
||||
Objective-C. Therefore, injecting `CP`-prefixed functions into the global scope is the intended design
|
||||
pattern here, not an anti-pattern or "pollution."
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
New compiler does not provide a pre-processor.
|
||||
The macro is expanded here to a concrete function.
|
||||
|
||||
The alternative is inlining at call site.
|
||||
On a cold call, this provides a very minor performance advantage.
|
||||
Conversely, it provides the Javascript engine fewer opportunities to optimize,
|
||||
which is only done when a call site is invoked.
|
||||
Additionally, it depends on individual maintainers to correctly implement the call every time.
|
||||
|
||||
The macro is expanded here precisely to maintain identical semantics.
|
||||
|
||||
Every current, popular browser engine optimizes a small, hot, monomorphic function like a numeric check almost immediately:
|
||||
|
||||
V8 (Chrome, Edge, Opera, Brave, Node) — tiered JIT (Ignition → Sparkplug → Maglev → TurboFan).
|
||||
A function called this often gets promoted within tens of calls.
|
||||
SpiderMonkey (Firefox) — Baseline Interpreter → Baseline JIT → Ion. Same pattern.
|
||||
JavaScriptCore (Safari, all iOS browsers, since iOS forces WebKit) — LLInt → Baseline → DFG → FTL.
|
||||
|
||||
All three engines specialize aggressively on exactly this shape of code: a tiny, pure, argument-type-stable function with no side effects. It is close to the ideal case for JIT optimization — the compiler will likely inline the call at the machine-code level, which is the same outcome as hand-inlining the expression, achieved automatically.
|
||||
|
||||
There is no browser in current popular use — desktop or mobile — where this function call would remain a meaningful cost.
|
||||
Additionally, modern hardware and Javascript engines are so much faster than in 2008, when Cappuccino was conceived,
|
||||
that even a cold execution of this function is trivial.
|
||||
The performance objection which originally required in-lining via a macro does not exist for current targets.
|
||||
|
||||
Javascript, Objective-J, C, and Objective-C all lack native namespacing.
|
||||
'CP' is the canonical namespace prefix used throughout Cappuccino to address potential collisions.
|
||||
It is reserved by convention.
|
||||
*/
|
||||
|
||||
/*
|
||||
Checks if a value is a valid, finite number.
|
||||
|
||||
This implements the legacy `_IS_NUMERIC` behavior exactly. It returns true for
|
||||
numbers and strings that can be successfully parsed into a finite number (e.g., 42, "3.14"),
|
||||
and false for NaN, Infinity, null, and purely non-numeric strings.
|
||||
|
||||
This specific logic (parseFloat + global isFinite) is deliberately preserved to prevent
|
||||
regressions in code that historically relied on its lenient string parsing, rather than
|
||||
using the stricter modern ES6 `Number.isFinite()`.
|
||||
|
||||
TODO: Modernize this check to use ES6 `Number.isFinite()`. This is currently deferred
|
||||
to maintain strict semantic continuity during the Go/Lisette toolchain migration and
|
||||
requires a full audit of all call sites to ensure string coercion is no longer expected.
|
||||
|
||||
@param n The value to evaluate.
|
||||
@return {Boolean} YES if the value is numeric, NO otherwise.
|
||||
*/
|
||||
function CPIsNumeric(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
Reference in New Issue
Block a user