diff --git a/include/networktables/NetworkTable.h b/include/networktables/NetworkTable.h index 8ee47a2e2c..2530353f97 100644 --- a/include/networktables/NetworkTable.h +++ b/include/networktables/NetworkTable.h @@ -267,6 +267,14 @@ class NetworkTable : public ITable { * @return False if the table key already exists with a different type */ bool PutNumber(llvm::StringRef key, double value) override; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultNumber(llvm::StringRef key, double defaultValue) override; /** * Gets the number associated with the given name. @@ -301,6 +309,15 @@ class NetworkTable : public ITable { * @return False if the table key already exists with a different type */ virtual bool PutString(llvm::StringRef key, llvm::StringRef value) override; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultString(llvm::StringRef key, + llvm::StringRef defaultValue) override; /** * Gets the string associated with the given name. @@ -336,6 +353,14 @@ class NetworkTable : public ITable { * @return False if the table key already exists with a different type */ virtual bool PutBoolean(llvm::StringRef key, bool value) override; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultBoolean(llvm::StringRef key, bool defaultValue) override; /** * Gets the boolean associated with the given name. @@ -376,6 +401,15 @@ class NetworkTable : public ITable { virtual bool PutBooleanArray(llvm::StringRef key, llvm::ArrayRef value) override; + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultBooleanArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) override; + /** * Returns the boolean array the key maps to. If the key does not exist or is * of different type, it will return the default value. @@ -403,6 +437,15 @@ class NetworkTable : public ITable { virtual bool PutNumberArray(llvm::StringRef key, llvm::ArrayRef value) override; + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultNumberArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) override; + /** * Returns the number array the key maps to. If the key does not exist or is * of different type, it will return the default value. @@ -426,6 +469,15 @@ class NetworkTable : public ITable { virtual bool PutStringArray(llvm::StringRef key, llvm::ArrayRef value) override; + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultStringArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) override; + /** * Returns the string array the key maps to. If the key does not exist or is * of different type, it will return the default value. @@ -448,6 +500,15 @@ class NetworkTable : public ITable { * @return False if the table key already exists with a different type */ virtual bool PutRaw(llvm::StringRef key, llvm::StringRef value) override; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultRaw(llvm::StringRef key, + llvm::StringRef defaultValue) override; /** * Returns the raw value (byte array) the key maps to. If the key does not @@ -471,6 +532,15 @@ class NetworkTable : public ITable { * @return False if the table key already exists with a different type */ bool PutValue(llvm::StringRef key, std::shared_ptr value) override; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultValue(llvm::StringRef key, + std::shared_ptr defaultValue) override; /** * Gets the value associated with a key as an object diff --git a/include/ntcore_c.h b/include/ntcore_c.h index 634380c314..d05875f3fd 100644 --- a/include/ntcore_c.h +++ b/include/ntcore_c.h @@ -174,6 +174,19 @@ struct NT_RpcCallInfo { */ void NT_GetEntryValue(const char *name, size_t name_len, struct NT_Value *value); + +/** Set Default Entry Value. + * Returns copy of current entry value if it exists. + * Otherwise, sets passed in value, and returns set value. + * Note that one of the type options is "unassigned". + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryValue(const char* name, size_t name_len, + const struct NT_Value *default_value); /** Set Entry Value. * Sets new entry value. If type of new value differs from the type of the @@ -802,6 +815,107 @@ NT_String *NT_GetEntryStringArray(const char *name, size_t name_len, unsigned long long *last_change, size_t *arr_size); +/* Set Default Values */ + +/** Set Default Entry Boolean. + * Sets the default for the specified key to be a boolean. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_boolean value to be set if name does not exist + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryBoolean(const char *name, size_t name_len, + int default_boolean); + +/** Set Default Entry Double. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_double value to be set if name does not exist + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryDouble(const char *name, size_t name_len, + double default_double); + +/** Set Default Entry String. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @param default_len length of value + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryString(const char *name, size_t name_len, + const char *default_value, size_t default_len); + +/** Set Default Entry Raw. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @param default_len length of value array + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryRaw(const char *name, size_t name_len, + const char *default_value, size_t default_len); + +/** Set Default Entry Boolean Array. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @param default_size size of value array + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryBooleanArray(const char *name, size_t name_len, + const int *default_value, + size_t default_size); + +/** Set Default Entry Double Array. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @param default_size size of value array + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryDoubleArray(const char *name, size_t name_len, + const double *default_value, + size_t default_size); + +/** Set Default Entry String Array. + * Sets the default for the specified key. + * If key exists with same type, does not set value. Otherwise + * sets value to the default. + * + * @param name entry name (UTF-8 string) + * @param name_len length of name in bytes + * @param default_value value to be set if name does not exist + * @param default_size size of value array + * @return 0 on error (value not set), 1 on success + */ +int NT_SetDefaultEntryStringArray(const char *name, size_t name_len, + const struct NT_String* default_value, + size_t default_size); + /* Entry Value Setters */ /** Set Entry Boolean diff --git a/include/ntcore_cpp.h b/include/ntcore_cpp.h index 7ed5140c72..aa8964b7f6 100644 --- a/include/ntcore_cpp.h +++ b/include/ntcore_cpp.h @@ -96,6 +96,17 @@ struct RpcCallInfo { */ std::shared_ptr GetEntryValue(StringRef name); +/** Set Default Entry Value + * Returns copy of current entry value if it exists. + * Otherwise, sets passed in value, and returns set value. + * Note that one of the type options is "unassigned". + * + * @param name entry name (UTF-8 string) + * @param value value to be set if name does not exist + * @return False on error (value not set), True on success + */ +bool SetDefaultEntryValue(StringRef name, std::shared_ptr value); + /** Set Entry Value. * Sets new entry value. If type of new value differs from the type of the * currently stored entry, returns error and does not update value. diff --git a/include/tables/ITable.h b/include/tables/ITable.h index 28ee6c0feb..d7804076ec 100644 --- a/include/tables/ITable.h +++ b/include/tables/ITable.h @@ -143,6 +143,15 @@ class ITable { * does not exist */ virtual std::shared_ptr GetValue(llvm::StringRef key) const = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultValue(llvm::StringRef key, + std::shared_ptr defaultValue) = 0; /** * Put a value in the table @@ -162,6 +171,14 @@ class ITable { * @return False if the table key already exists with a different type */ virtual bool PutNumber(llvm::StringRef key, double value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultNumber(llvm::StringRef key, double defaultValue) = 0; /** * Gets the number associated with the given name. @@ -195,6 +212,15 @@ class ITable { * @return False if the table key already exists with a different type */ virtual bool PutString(llvm::StringRef key, llvm::StringRef value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultString(llvm::StringRef key, + llvm::StringRef defaultValue) = 0; /** * Gets the string associated with the given name. @@ -233,6 +259,14 @@ class ITable { * @return False if the table key already exists with a different type */ virtual bool PutBoolean(llvm::StringRef key, bool value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultBoolean(llvm::StringRef key, bool defaultValue) = 0; /** * Gets the boolean associated with the given name. @@ -271,6 +305,15 @@ class ITable { */ virtual bool PutBooleanArray(llvm::StringRef key, llvm::ArrayRef value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultBooleanArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) = 0; /** * Returns the boolean array the key maps to. If the key does not exist or is @@ -298,6 +341,15 @@ class ITable { */ virtual bool PutNumberArray(llvm::StringRef key, llvm::ArrayRef value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultNumberArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) = 0; /** * Returns the number array the key maps to. If the key does not exist or is @@ -321,6 +373,15 @@ class ITable { */ virtual bool PutStringArray(llvm::StringRef key, llvm::ArrayRef value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultStringArray(llvm::StringRef key, + llvm::ArrayRef defaultValue) = 0; /** * Returns the string array the key maps to. If the key does not exist or is @@ -343,6 +404,15 @@ class ITable { * @return False if the table key already exists with a different type */ virtual bool PutRaw(llvm::StringRef key, llvm::StringRef value) = 0; + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doesn't exist. + * @returns False if the table key exists with a different type + */ + virtual bool SetDefaultRaw(llvm::StringRef key, + llvm::StringRef defaultValue) = 0; /** * Returns the raw value (byte array) the key maps to. If the key does not diff --git a/java/lib/NetworkTablesJNI.cpp b/java/lib/NetworkTablesJNI.cpp index 8520cd5117..5da7c81dc6 100644 --- a/java/lib/NetworkTablesJNI.cpp +++ b/java/lib/NetworkTablesJNI.cpp @@ -915,6 +915,90 @@ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkT return ToJavaStringArray(env, val->GetStringArray()); } +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultBoolean + * Signature: (Ljava/lang/String;Z)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultBoolean + (JNIEnv *env, jclass, jstring key, jboolean defaultValue) +{ + return nt::SetDefaultEntryValue(JavaStringRef(env, key), + nt::Value::MakeBoolean(defaultValue != JNI_FALSE)); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultDouble + * Signature: (Ljava/lang/String;D)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultDouble + (JNIEnv *env, jclass, jstring key, jdouble defaultValue) +{ + return nt::SetDefaultEntryValue(JavaStringRef(env, key), + nt::Value::MakeDouble(defaultValue)); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultString + * Signature: (Ljava/lang/String;Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultString + (JNIEnv *env, jclass, jstring key, jstring defaultValue) +{ + return nt::SetDefaultEntryValue(JavaStringRef(env, key), + nt::Value::MakeString(JavaStringRef(env, defaultValue))); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultRaw + * Signature: (Ljava/lang/String;[B)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultRaw + (JNIEnv *env, jclass, jstring key, jbyteArray defaultValue) +{ + auto v = FromJavaRaw(env, defaultValue); + return nt::SetDefaultEntryValue(JavaStringRef(env, key), v); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultBooleanArray + * Signature: (Ljava/lang/String;[Z)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultBooleanArray + (JNIEnv *env, jclass, jstring key, jbooleanArray defaultValue) +{ + auto v = FromJavaBooleanArray(env, defaultValue); + return nt::SetDefaultEntryValue(JavaStringRef(env, key), v); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultDoubleArray + * Signature: (Ljava/lang/String;[D)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultDoubleArray + (JNIEnv *env, jclass, jstring key, jdoubleArray defaultValue) +{ + auto v = FromJavaDoubleArray(env, defaultValue); + return nt::SetDefaultEntryValue(JavaStringRef(env, key), v); +} + +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: setDefaultStringArray + * Signature: (Ljava/lang/String;[Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultStringArray + (JNIEnv *env, jclass, jstring key, jobjectArray defaultValue) +{ + auto v = FromJavaStringArray(env, defaultValue); + return nt::SetDefaultEntryValue(JavaStringRef(env, key), v); +} + /* * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI * Method: setEntryFlags diff --git a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTable.java b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTable.java index ad1a876e8b..962780308f 100644 --- a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTable.java +++ b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTable.java @@ -502,6 +502,14 @@ public class NetworkTable implements ITable, IRemote { public boolean putNumber(String key, double value) { return NetworkTablesJNI.putDouble(path + PATH_SEPARATOR + key, value); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultNumber(String key, double defaultValue) { + return NetworkTablesJNI.setDefaultDouble(path + PATH_SEPARATOR + key, + defaultValue); + } /** * {@inheritDoc} @@ -529,6 +537,14 @@ public class NetworkTable implements ITable, IRemote { public boolean putString(String key, String value) { return NetworkTablesJNI.putString(path + PATH_SEPARATOR + key, value); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultString(String key, String defaultValue) { + return NetworkTablesJNI.setDefaultString(path + PATH_SEPARATOR + key, + defaultValue); + } /** * {@inheritDoc} @@ -556,6 +572,14 @@ public class NetworkTable implements ITable, IRemote { public boolean putBoolean(String key, boolean value) { return NetworkTablesJNI.putBoolean(path + PATH_SEPARATOR + key, value); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultBoolean(String key, boolean defaultValue) { + return NetworkTablesJNI.setDefaultBoolean(path + PATH_SEPARATOR + key, + defaultValue); + } /** * {@inheritDoc} @@ -591,6 +615,22 @@ public class NetworkTable implements ITable, IRemote { public boolean putBooleanArray(String key, Boolean[] value) { return putBooleanArray(key, toNative(value)); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultBooleanArray(String key, boolean[] defaultValue) { + return NetworkTablesJNI.setDefaultBooleanArray(path + PATH_SEPARATOR + key, + defaultValue); + } + + /** + * {@inheritDoc} + */ + public boolean setDefaultBooleanArray(String key, Boolean[] defaultValue) { + return NetworkTablesJNI.setDefaultBooleanArray(path + PATH_SEPARATOR + key, + toNative(defaultValue)); + } /** * {@inheritDoc} @@ -638,6 +678,22 @@ public class NetworkTable implements ITable, IRemote { public boolean putNumberArray(String key, Double[] value) { return putNumberArray(key, toNative(value)); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultNumberArray(String key, double[] defaultValue) { + return NetworkTablesJNI.setDefaultDoubleArray(path + PATH_SEPARATOR + key, + defaultValue); + } + + /** + * {@inheritDoc} + */ + public boolean setDefaultNumberArray(String key, Double[] defaultValue) { + return NetworkTablesJNI.setDefaultDoubleArray(path + PATH_SEPARATOR + key, + toNative(defaultValue)); + } /** * {@inheritDoc} @@ -677,7 +733,15 @@ public class NetworkTable implements ITable, IRemote { public boolean putStringArray(String key, String[] value) { return NetworkTablesJNI.putStringArray(path + PATH_SEPARATOR + key, value); } - + + /** + * {@inheritDoc} + */ + public boolean setDefaultStringArray(String key, String[] defaultValue) { + return NetworkTablesJNI.setDefaultStringArray(path + PATH_SEPARATOR + key, + defaultValue); + } + /** * {@inheritDoc} * @deprecated This exception-raising method has been replaced by the @@ -704,6 +768,14 @@ public class NetworkTable implements ITable, IRemote { public boolean putRaw(String key, byte[] value) { return NetworkTablesJNI.putRaw(path + PATH_SEPARATOR + key, value); } + + /** + * {@inheritDoc} + */ + public boolean setDefaultRaw(String key, byte[] defaultValue) { + return NetworkTablesJNI.setDefaultRaw(path + PATH_SEPARATOR + key, + defaultValue); + } /** * {@inheritDoc} diff --git a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java index 393238d516..a4c4a21990 100644 --- a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java +++ b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java @@ -106,6 +106,14 @@ public class NetworkTablesJNI { public static native double[] getDoubleArray(String key, double[] defaultValue); public static native String[] getStringArray(String key, String[] defaultValue); + public static native boolean setDefaultBoolean(String key, boolean defaultValue); + public static native boolean setDefaultDouble(String key, double defaultValue); + public static native boolean setDefaultString(String key, String defaultValue); + public static native boolean setDefaultRaw(String key, byte[] defaultValue); + public static native boolean setDefaultBooleanArray(String key, boolean[] defaultValue); + public static native boolean setDefaultDoubleArray(String key, double[] defaultValue); + public static native boolean setDefaultStringArray(String key, String[] defaultValue); + public static native void setEntryFlags(String key, int flags); public static native int getEntryFlags(String key); diff --git a/java/src/edu/wpi/first/wpilibj/tables/ITable.java b/java/src/edu/wpi/first/wpilibj/tables/ITable.java index 81d12be241..d126cf1165 100644 --- a/java/src/edu/wpi/first/wpilibj/tables/ITable.java +++ b/java/src/edu/wpi/first/wpilibj/tables/ITable.java @@ -165,6 +165,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putNumber(String key, double value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultNumber(String key, double defaultValue); + /** * Returns the number the key maps to. * @param key the key to look up @@ -193,6 +202,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putString(String key, String value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultString(String key, String defaultValue); + /** * Returns the string the key maps to. * @param key the key to look up @@ -221,6 +239,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putBoolean(String key, boolean value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultBoolean(String key, boolean defaultValue); + /** * Returns the boolean the key maps to. * @param key the key to look up @@ -249,6 +276,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putBooleanArray(String key, boolean[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultBooleanArray(String key, boolean[] defaultValue); + /** * Put a boolean array in the table * @param key the key to be assigned to @@ -256,6 +292,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putBooleanArray(String key, Boolean[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultBooleanArray(String key, Boolean[] defaultValue); + /** * Returns the boolean array the key maps to. * @param key the key to look up @@ -293,6 +338,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putNumberArray(String key, double[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultNumberArray(String key, double[] defaultValue); + /** * Put a number array in the table * @param key the key to be assigned to @@ -300,6 +354,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putNumberArray(String key, Double[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultNumberArray(String key, Double[] defaultValue); + /** * Returns the number array the key maps to. * @param key the key to look up @@ -337,6 +400,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putStringArray(String key, String[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultStringArray(String key, String[] defaultValue); + /** * Returns the string array the key maps to. * @param key the key to look up @@ -365,6 +437,15 @@ public interface ITable { * @return False if the table key already exists with a different type */ public boolean putRaw(String key, byte[] value); + + /** + * Gets the current value in the table, setting it if it does not exist. + * @param key the key + * @param defaultValue the default value to set if key doens't exist. + * @return False if the table key exists with a different type + */ + public boolean setDefaultRaw(String key, byte[] defaultValue); + /** * Put a raw value (bytes from a byte buffer) in the table * @param key the key to be assigned to diff --git a/ntcore.def b/ntcore.def index f9348c4e6b..8c451ed2a0 100644 --- a/ntcore.def +++ b/ntcore.def @@ -82,6 +82,15 @@ NT_SetRpcServerOnStart @84 NT_SetRpcServerOnExit @85 NT_StartClientMulti @86 +NT_SetDefaultEntryValue @87 +NT_SetDefaultEntryBoolean @88 +NT_SetDefaultEntryDouble @89 +NT_SetDefaultEntryString @90 +NT_SetDefaultEntryRaw @91 +NT_SetDefaultEntryBooleanArray @92 +NT_SetDefaultEntryDoubleArray @93 +NT_SetDefaultEntryStringArray @94 + ; JNI functions JNI_OnLoad JNI_OnUnload diff --git a/src/Storage.cpp b/src/Storage.cpp index 17c4d40a62..75b8b8d174 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -464,6 +464,48 @@ std::shared_ptr Storage::GetEntryValue(StringRef name) const { return i == m_entries.end() ? nullptr : i->getValue()->value; } +bool Storage::SetDefaultEntryValue(StringRef name, + std::shared_ptr value) { + if (!value) return false; // can't compare to a null value + if (name.empty()) return false; // can't compare empty name + std::unique_lock lock(m_mutex); + auto& new_entry = m_entries[name]; + if (new_entry) { // entry already exists + auto old_value = new_entry->value; + // if types match return true + if (old_value && old_value->type() == value->type()) return true; + else return false; // entry exists but doesn't match type + } + + // if we've gotten here, entry does not exist, and we can write it. + new_entry.reset(new Entry(name)); + Entry* entry = new_entry.get(); + // don't need to compare old value as we know it will assign + entry->value = value; + + // if we're the server, assign an id if it doesn't have one + if (m_server && entry->id == 0xffff) { + unsigned int id = m_idmap.size(); + entry->id = id; + m_idmap.push_back(entry); + } + + // notify (for local listeners) + if (m_notifier.local_notifiers()) { + // always a new entry if we got this far + m_notifier.NotifyEntry(name, value, NT_NOTIFY_NEW | NT_NOTIFY_LOCAL); + } + + // generate message + if (!m_queue_outgoing) return true; + auto queue_outgoing = m_queue_outgoing; + auto msg = Message::EntryAssign(name, entry->id, entry->seq_num.value(), + value, entry->flags); + lock.unlock(); + queue_outgoing(msg, nullptr, nullptr); + return true; +} + bool Storage::SetEntryValue(StringRef name, std::shared_ptr value) { if (name.empty()) return true; if (!value) return true; diff --git a/src/Storage.h b/src/Storage.h index fd6b7b7e04..92fcbddde8 100644 --- a/src/Storage.h +++ b/src/Storage.h @@ -67,6 +67,7 @@ class Storage { // User functions. These are the actual implementations of the corresponding // user API functions in ntcore_cpp. std::shared_ptr GetEntryValue(StringRef name) const; + bool SetDefaultEntryValue(StringRef name, std::shared_ptr value); bool SetEntryValue(StringRef name, std::shared_ptr value); void SetEntryTypeValue(StringRef name, std::shared_ptr value); void SetEntryFlags(StringRef name, unsigned int flags); diff --git a/src/networktables/NetworkTable.cpp b/src/networktables/NetworkTable.cpp index 23a089725c..8b1149b530 100644 --- a/src/networktables/NetworkTable.cpp +++ b/src/networktables/NetworkTable.cpp @@ -305,6 +305,13 @@ bool NetworkTable::PutNumber(StringRef key, double value) { return nt::SetEntryValue(path, nt::Value::MakeDouble(value)); } +bool NetworkTable::SetDefaultNumber(StringRef key, double defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeDouble(defaultValue)); +} + double NetworkTable::GetNumber(StringRef key) const { llvm::SmallString<128> path(m_path); path += PATH_SEPARATOR_CHAR; @@ -332,6 +339,13 @@ bool NetworkTable::PutString(StringRef key, StringRef value) { return nt::SetEntryValue(path, nt::Value::MakeString(value)); } +bool NetworkTable::SetDefaultString(StringRef key, StringRef defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeString(defaultValue)); +} + std::string NetworkTable::GetString(StringRef key) const { llvm::SmallString<128> path(m_path); path += PATH_SEPARATOR_CHAR; @@ -360,6 +374,13 @@ bool NetworkTable::PutBoolean(StringRef key, bool value) { return nt::SetEntryValue(path, nt::Value::MakeBoolean(value)); } +bool NetworkTable::SetDefaultBoolean(StringRef key, bool defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeBoolean(defaultValue)); +} + bool NetworkTable::GetBoolean(StringRef key) const { llvm::SmallString<128> path(m_path); path += PATH_SEPARATOR_CHAR; @@ -388,6 +409,14 @@ bool NetworkTable::PutBooleanArray(llvm::StringRef key, return nt::SetEntryValue(path, nt::Value::MakeBooleanArray(value)); } +bool NetworkTable::SetDefaultBooleanArray(StringRef key, + llvm::ArrayRef defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeBooleanArray(defaultValue)); +} + std::vector NetworkTable::GetBooleanArray( llvm::StringRef key, llvm::ArrayRef defaultValue) const { llvm::SmallString<128> path(m_path); @@ -407,6 +436,14 @@ bool NetworkTable::PutNumberArray(llvm::StringRef key, return nt::SetEntryValue(path, nt::Value::MakeDoubleArray(value)); } +bool NetworkTable::SetDefaultNumberArray(StringRef key, + llvm::ArrayRef defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeDoubleArray(defaultValue)); +} + std::vector NetworkTable::GetNumberArray( llvm::StringRef key, llvm::ArrayRef defaultValue) const { llvm::SmallString<128> path(m_path); @@ -426,6 +463,14 @@ bool NetworkTable::PutStringArray(llvm::StringRef key, return nt::SetEntryValue(path, nt::Value::MakeStringArray(value)); } +bool NetworkTable::SetDefaultStringArray(StringRef key, + llvm::ArrayRef defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeStringArray(defaultValue)); +} + std::vector NetworkTable::GetStringArray( llvm::StringRef key, llvm::ArrayRef defaultValue) const { llvm::SmallString<128> path(m_path); @@ -444,6 +489,14 @@ bool NetworkTable::PutRaw(llvm::StringRef key, llvm::StringRef value) { return nt::SetEntryValue(path, nt::Value::MakeRaw(value)); } +bool NetworkTable::SetDefaultRaw(StringRef key, + StringRef defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, nt::Value::MakeRaw(defaultValue)); +} + std::string NetworkTable::GetRaw(llvm::StringRef key, llvm::StringRef defaultValue) const { llvm::SmallString<128> path(m_path); @@ -462,6 +515,14 @@ bool NetworkTable::PutValue(StringRef key, std::shared_ptr value) { return nt::SetEntryValue(path, value); } +bool NetworkTable::SetDefaultValue(StringRef key, + std::shared_ptr defaultValue) { + llvm::SmallString<128> path(m_path); + path += PATH_SEPARATOR_CHAR; + path += key; + return nt::SetDefaultEntryValue(path, defaultValue); +} + std::shared_ptr NetworkTable::GetValue(StringRef key) const { llvm::SmallString<128> path(m_path); path += PATH_SEPARATOR_CHAR; diff --git a/src/ntcore_c.cpp b/src/ntcore_c.cpp index 15e87850a0..395dcdda0d 100644 --- a/src/ntcore_c.cpp +++ b/src/ntcore_c.cpp @@ -124,6 +124,12 @@ void NT_GetEntryValue(const char *name, size_t name_len, ConvertToC(*v, value); } +int NT_SetDefaultEntryValue(const char* name, size_t name_len, + const struct NT_Value *set_value) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + ConvertFromC(*set_value)); +} + int NT_SetEntryValue(const char *name, size_t name_len, const struct NT_Value *value) { return nt::SetEntryValue(StringRef(name, name_len), ConvertFromC(*value)); @@ -701,6 +707,57 @@ NT_String *NT_GetValueStringArray(const struct NT_Value *value, return arr; } +int NT_SetDefaultEntryBoolean(const char *name, size_t name_len, + int default_boolean) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeBoolean(default_boolean != 0)); +} + +int NT_SetDefaultEntryDouble(const char *name, size_t name_len, + double default_double) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeDouble(default_double)); +} + +int NT_SetDefaultEntryString(const char *name, size_t name_len, + const char *default_value, size_t default_len) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeString(StringRef(default_value, + default_len))); +} + +int NT_SetDefaultEntryRaw(const char *name, size_t name_len, + const char *default_value, size_t default_len) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeString(StringRef(default_value, + default_len))); +} + +int NT_SetDefaultEntryBooleanArray(const char *name, size_t name_len, + const int *default_value, + size_t default_size) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeBooleanArray(llvm::makeArrayRef(default_value, default_size))); +} + +int NT_SetDefaultEntryDoubleArray(const char *name, size_t name_len, const double *default_value, + size_t default_size) { + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeDoubleArray(llvm::makeArrayRef(default_value, default_size))); +} + +int NT_SetDefaultEntryStringArray(const char *name, size_t name_len, + const struct NT_String* default_value, + size_t default_size) { + std::vector vec; + vec.reserve(default_size); + for (size_t i = 0; i < default_size; ++i) + vec.push_back(ConvertFromC(default_value[i])); + + return nt::SetDefaultEntryValue(StringRef(name, name_len), + Value::MakeStringArray(std::move(vec))); +} + int NT_GetEntryBoolean(const char *name, size_t name_len, unsigned long long *last_change, int *v_boolean) { auto v = nt::GetEntryValue(StringRef(name, name_len)); diff --git a/src/ntcore_cpp.cpp b/src/ntcore_cpp.cpp index bdc1172199..9eae17306b 100644 --- a/src/ntcore_cpp.cpp +++ b/src/ntcore_cpp.cpp @@ -29,6 +29,10 @@ std::shared_ptr GetEntryValue(StringRef name) { return Storage::GetInstance().GetEntryValue(name); } +bool SetDefaultEntryValue(StringRef name, std::shared_ptr value) { + return Storage::GetInstance().SetDefaultEntryValue(name, value); +} + bool SetEntryValue(StringRef name, std::shared_ptr value) { return Storage::GetInstance().SetEntryValue(name, value); } diff --git a/test/unit/StorageTest.cpp b/test/unit/StorageTest.cpp index 75794c60b9..42880491ad 100644 --- a/test/unit/StorageTest.cpp +++ b/test/unit/StorageTest.cpp @@ -288,6 +288,106 @@ TEST_P(StorageTestEmpty, SetEntryValueEmptyValue) { EXPECT_TRUE(outgoing.empty()); } +TEST_P(StorageTestEmpty, SetDefaultEntryAssignNew) { + // brand new entry + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("foo", value); + EXPECT_TRUE(ret_val); + EXPECT_EQ(value, GetEntry("foo")->value); + + ASSERT_EQ(1u, outgoing.size()); + EXPECT_FALSE(outgoing[0].only); + EXPECT_FALSE(outgoing[0].except); + auto msg = outgoing[0].msg; + EXPECT_EQ(Message::kEntryAssign, msg->type()); + EXPECT_EQ("foo", msg->str()); + if (GetParam()) + EXPECT_EQ(0u, msg->id()); // assigned as server + else + EXPECT_EQ(0xffffu, msg->id()); // not assigned as client + EXPECT_EQ(0u, msg->seq_num_uid()); + EXPECT_EQ(value, msg->value()); + EXPECT_EQ(0u, msg->flags()); +} + +TEST_P(StorageTestPopulateOne, SetDefaultEntryExistsSameType) { + // existing entry + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("foo", value); + EXPECT_TRUE(ret_val); + EXPECT_NE(value, GetEntry("foo")->value); + + EXPECT_TRUE(outgoing.empty()); +} + +TEST_P(StorageTestPopulateOne, SetDefaultEntryExistsDifferentType) { + // existing entry is boolean + auto value = Value::MakeDouble(2.0); + auto ret_val = storage.SetDefaultEntryValue("foo", value); + EXPECT_FALSE(ret_val); + // should not have updated value in table if it already existed. + EXPECT_NE(value, GetEntry("foo")->value); + + EXPECT_TRUE(outgoing.empty()); +} + +TEST_P(StorageTestEmpty, SetDefaultEntryEmptyName) { + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("", value); + EXPECT_FALSE(ret_val); + auto entry = GetEntry("foo"); + EXPECT_FALSE(entry->value); + EXPECT_EQ(0u, entry->flags); + EXPECT_EQ("foobar", entry->name); // since GetEntry uses the tmp_entry. + EXPECT_EQ(0xffffu, entry->id); + EXPECT_EQ(SequenceNumber(), entry->seq_num); + EXPECT_TRUE(entries().empty()); + EXPECT_TRUE(idmap().empty()); + EXPECT_TRUE(outgoing.empty()); +} + +TEST_P(StorageTestEmpty, SetDefaultEntryEmptyValue) { + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("", nullptr); + EXPECT_FALSE(ret_val); + auto entry = GetEntry("foo"); + EXPECT_FALSE(entry->value); + EXPECT_EQ(0u, entry->flags); + EXPECT_EQ("foobar", entry->name); // since GetEntry uses the tmp_entry. + EXPECT_EQ(0xffffu, entry->id); + EXPECT_EQ(SequenceNumber(), entry->seq_num); + EXPECT_TRUE(entries().empty()); + EXPECT_TRUE(idmap().empty()); + EXPECT_TRUE(outgoing.empty()); +} + +TEST_P(StorageTestPopulated, SetDefaultEntryEmptyName) { + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("", value); + EXPECT_FALSE(ret_val); + // assert that no entries get added + EXPECT_EQ(4u, entries().size()); + if (GetParam()) + EXPECT_EQ(4u, idmap().size()); + else + EXPECT_EQ(0u, idmap().size()); + EXPECT_TRUE(outgoing.empty()); +} + +TEST_P(StorageTestPopulated, SetDefaultEntryEmptyValue) { + auto value = Value::MakeBoolean(true); + auto ret_val = storage.SetDefaultEntryValue("", nullptr); + EXPECT_FALSE(ret_val); + // assert that no entries get added + EXPECT_EQ(4u, entries().size()); + if (GetParam()) + EXPECT_EQ(4u, idmap().size()); + else + EXPECT_EQ(0u, idmap().size()); + EXPECT_TRUE(outgoing.empty()); +} + + TEST_P(StorageTestEmpty, SetEntryFlagsNew) { // flags setting doesn't create an entry storage.SetEntryFlags("foo", 0u);